State initialization inside a functional component (without infinite looping)

react setstate infinite loop
too many re-renders. react limits the number of renders to prevent an infinite loop.
react infinite loop
useeffect infinite loop
react hooks
how to debug react infinite loop
react context infinite loop
componentdidmount

I have a functional component that holds custom viewport values in its state, so it must use event listeners and measure the window size:

const AppWrap = () => {

  // custom vw and vh vars
  const [vw, setvw] = useState();
  const [vh, setvh] = useState();

  // gets the inner height/width to act as viewport dimensions (cross-platform benefits)
  const setViewportVars = () => {

    const viewportWidth = window.innerWidth;
    const viewportHeight = window.innerHeight;

    // can be accessed in scss as vw(n), vh(n) OR in css as --vw * n, --vh * n
    document.documentElement.style.setProperty('--vw', `${viewportWidth / 100}px`);
    document.documentElement.style.setProperty('--vh', `${viewportHeight / 100}px`);

    // can be accessed in child components as vw * n or vh * n
    setvw(viewportWidth / 100);
    setvh(viewportHeight / 100);

  }

  // I'd like to run this function *once* when the component is initialized
  setViewportVars();

  // add listeners
  window.addEventListener('resize', setViewportVars);
  window.addEventListener('orientationchange', setViewportVars);
  window.addEventListener('fullscreenchange', setViewportVars);

  return (
    <App vw={vw} vh={vh}/>
  );

}

The above code produces an error: Too many re-renders. React limits the number of renders to prevent an infinite loop.

I can wrap setViewportVars() in useEffect, but I don't see why this is necessary. My understanding of functional components is that they only run code outside of the return statement once, and that only the JSX would re-render on a state change.

You have to use useEffect and pass empty array as dependencies, so this will only be excecuted once just like componentDidMount:

useEffect(() => {
  setViewportVars();

  // add listeners
  window.addEventListener('resize', setViewportVars);
  window.addEventListener('orientationchange', setViewportVars);
  window.addEventListener('fullscreenchange', setViewportVars);
}, []);

Calling setState in render causes infinite loop � Issue #5591 , This may seem really silly to do to call setState in render. remotely related to modifying any component's state within a render function. initModal.bind(this, mRecord); // in child 2 <button onClick={this.props.init}/> and Child2 elements with different values, so no, I don't know mRecord in the parent. It lets us keep local state in a function component. Line 4: Inside the Example component, we declare a new state variable by calling the useState Hook. It returns a pair of values, to which we give names. We’re calling our variable count because it holds the number of button clicks.

The answer to why you need to useEffect() to prevent the infinite re-render:

<AppWrap> has state {vw} and {vh}. When <AppWrap>is fired, setViewportVars() immediately runs and updates that state. Because you updated the state, setViewportVars() is then fired again (to keep in line with the react one way data flow which updates the state of {vw/vh} and causes a re-firing of AppWrap ...which causes a re-firing of setViewportVars(). At no point here have we allowed the DOM to get painted by the browser, we are just repeating the loop of:

init component > getHeight/Width > updateState > re-render component > getHeight/Width > ...

useEffect behaves differently than a regular render. useEffect fires only after a the DOM has been painted by the browser. Which means that the first cycle would finish (init component > browser paints DOM > useEffect(getHeight/Width) > |if state aka viewsize changed?| > re-render)

For more info, check out Dan Abramov's blog on useEffect

Infinite loop (Maximum call stack size exceeded) when passing , EDIT: Apparently it only happens when the component where the form is function, for example: const mapStateToProps = state I can reproduce by trying to call this.props.initialize in componentWillMount with undefined values, Resolvendo bug de loop infinito aplicando a solu��o sugerida no link: Fetching inside useEffect() isn’t a problem on its own, but we encounter a problem if we try to use the data from our fetch to set the state. This Hook breaks our program with an infinite loop

So in your case what happens is basically you call the function it will update the state, so again component will load again function will call so basically that goes to infinite loop

Solution

you can useEffect, so in useEffect if you pass the second argument which is an array as empty it will called only one time like the componentDidMount

useEffect(() => {
  setViewportVars()
}, [])

So if you pass second argument

  1. Passing nothing, like useEffect(() => {}) - it will call every time.

  2. Passing an empty array useEffect(() => {}, []) - it will call one time.

  3. Passing array deps, whenever the array dependencies changes it will execute the code block inside the usEffect.

    useEffect(() => { // some logic }, [user])

An imperative guide to setState in React, The change in state for React components can be a result of triggers from while those that do not have states are referred to as stateless components. in a condition like in the example below, or you'll cause an infinite loop: setState() is async, meaning there is no guarantee that the state has been� Experiment: If you would leave the second argument of the Effect Hook empty, you would run into an infinite loop of increasing the count by 1, because the Effect Hook always runs after state has changed. Since the Effect Hook triggers another state change, it will run again and again to increase the count. React Functional Component: Update

const AppWrap = () => {

    // custom vw and vh vars
    const [vw, setvw] = useState();
    const [vh, setvh] = useState();

    // gets the inner height/width to act as viewport dimensions (cross-platform benefits)
    const setViewportVars = useCallback(() => {

        const viewportWidth = window.innerWidth;
        const viewportHeight = window.innerHeight;

        // can be accessed in scss as vw(n), vh(n) OR in css as --vw * n, --vh * n
        document.documentElement.style.setProperty('--vw', `${viewportWidth / 100}px`);
        document.documentElement.style.setProperty('--vh', `${viewportHeight / 100}px`);

        // can be accessed in child components as vw * n or vh * n
        setvw(viewportWidth / 100);
        setvh(viewportHeight / 100);

    }, []);



    useEffect(() => {
        window.addEventListener('resize', setViewportVars);
        window.addEventListener('orientationchange', setViewportVars);
        window.addEventListener('fullscreenchange', setViewportVars);
        return () => {
            window.removeEventListener('resize', setViewportVars);
            window.removeEventListener('orientationchange', setViewportVars);
            window.removeEventListener('fullscreenchange', setViewportVars);
        }
    }, []);

    useEffect(() => {
        // I'd like to run this function *once* when the component is initialized
        setViewportVars();
    }, []);


    return (
        <App vw={vw} vh={vh} />
    );

}

Frustrations with React Hooks, They let you use state, and other React features without writing a class. One of the biggest complaints is that you often have to repeat logic in arrays and wrapping functions in useCallback to avoid the stale state or infinite re-rendering. Having Hooks callable in every render of a functional component� The state is information hidden inside a component. The component can modify its state, without parents knowing about it. I prefer functional components because they are simple. To enable state management for functional components, you need useState() hook. The guide step by step explains how to work with useState() hook.

React Hooks with closures: useState v/s useReducer, setState , we use it to set the state(s) of our functional component. Code snippet of useHistory using useState without callbacks and times in a short span of time, our code goes into an infinite loop. Now, the issue is because of the variable state being initialized inside the functional component, hence� Here's what will cause an infinite loop, assuming you're not doing any state change checks: setState inside componentWillUpdate; setState inside componentDidUpdate; setState inside render (this is usually accidental) setState inside getSnapshotBeforeUpdate; Make sure you're not doing any of the above and you shouldn't see an infinite loop.

React Hooks Crash Course, Prior to React Hooks, you managed state like this: In functional components, you got no lifecycle methods - but of course But in addition, you introduced an infinite loop because calling So you're basically using componentDidMount here - which often is the better place for initialization work anyways. As you can see from the code above the component's internal state gets mutated by this.setState when clicking the button. The text's button in turns reacts to this change and receives the updated text. With React hooks its possible to express the same logic without an ES6 class. Updating the state in React without setState

Infinite useEffect loop when using Redux with React Hooks, No matter what I try, the useEffect function gets into an infinite loop and are state variables that are initialized to specific values on 'component mount' I would Am I using this wrong in that Redux isn't meant to be used with hooks like this? Running a function only once after component mounts is such a common pattern that it justifies a hook of it's own that hides implementation details. const useMountEffect = (fun) => useEffect(fun, []) Use it in any functional component. function MyComponent() { useMountEffect(function) // function will run only once after it has mounted.

Comments
  • In your case when component loads it calls the function which changes states so again it calls the component again it changes so it . goes to infinite condition inorder . to avoid this you need to useEffect , added the answer kindly check it :)
  • This is correct - thanks! After reading up on this some more, I would also note that instead of listing an empty dep array, the recommendation is to move setViewportVars into useEffect (reactjs.org/docs/…)
  • If I remove <App vw={vw} vh={vh}/> (i.e. make AppWrap render nothing) I get the same looping behavior. So I'm not sure that the sequencing/connection you are drawing between the two components is accurate.
  • 1. wrap your callback with useCallback 2. bind your events inside use effect and unbind inside the return function 2. invoke setViewportVars from useEffect with empty array as dependcies
  • I see how this would work, but it doesn't square with recommendations in the docs. For instance: "every value referenced inside the callback should also appear in the dependencies array" (reactjs.org/docs/hooks-reference.html#usecallback) Similar recommendations around empty array deps can be found here: overreacted.io/a-complete-guide-to-useeffect
  • After reading up on this a bit more, I think that the proper way way to do this is actually to pull setViewportVars into useEffect instead of wrapping it in useCallback (reactjs.org/docs/…)