JustANewCoder
JustANewCoder

Reputation: 437

Basically same code but one cause infinite loop in useeffect

Sorry, reactjs beginner here, with below two codes, I don't get why when I use the "First code" I get infinite loop (infinite log out '123' in my browser console) and when I use "Second code", I don't get infinite loop (only log out two '123' in my browser console), how come I am not getting infinite loop with "Second code" when I am getting infinite loop with my "First code"?

(First code) Cause infinite loop:

[Parent.js]
const randomFunc = (dataFromChildComponent) => {
  setData(dataFromChildComponent);
};

[Child.js]
useEffect(() => {
  fetch("https://jsonplaceholder.typicode.com/posts")
    .then((response) => response.json())
    .then((post) => {
      randomFunc(post);
      console.log('123');
    });
}, [randomFunc]);

const {useState, useEffect} = React;
const Parent = () => {
  const [data, setData] = useState([]);
  const randomFunc = (dataFromChildComponent) => {
    setData(dataFromChildComponent);
  };
  
  return <div>
    <p>Parent data: {JSON.stringify(data, null,2)}</p>
    <p>Child: <Child randomFunc={randomFunc} data={data}/></p>;
  </div>
}


const Child = ({randomFunc, data}) => {
  useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((response) => response.json())
      .then((post) => {
        randomFunc(post);
        console.log('123');
      });
  }, [randomFunc]);
  
  return <p>Child data - {JSON.stringify(data, null, 2)}</p>;
}

ReactDOM.render(<Parent />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>

(Second code) Does not cause infinite loop:

[Parent.js]
const randomFunc = (dataFromChildComponent) => {
  setData(dataFromChildComponent);
};

[Child.js]
useEffect(() => {
   randomFunc('Some data!');
   console.log('123');
}, [randomFunc]);

const {useState, useEffect} = React;
const Parent = () => {
  const [data, setData] = useState([]);
  const randomFunc = (dataFromChildComponent) => {
    setData(dataFromChildComponent);
  };
  
  return <div>
    <p>Parent data: {data}</p>
    <p>Child: <Child randomFunc={randomFunc} data={data}/></p>
  </div>
}


const Child = ({randomFunc, data}) => {
  useEffect(() => {
    randomFunc('Some data!');
    console.log('123');
  }, [randomFunc]);
  
  return <p>Child data - {data}</p>
}

ReactDOM.render(<Parent />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>

Upvotes: 0

Views: 104

Answers (1)

Sumit Surana
Sumit Surana

Reputation: 1584

First Program:

As state changes randomFunc in parent is also evaluated again, thus leading to prop in child component to change and leading to infinite cycle. To stop that from happening you can use https://reactjs.org/docs/hooks-reference.html#usecallback for randomFunc in parent.js like below

const randomFunc = useCallback((dataFromChildComponent) => {
  setData(dataFromChildComponent);
}, []);

Adding useCallback will create a memoized version of the function, which won't change till something in the dependency array doesn't change. In this case as there is no dependency, once it is evaluated it won't change again.

Second Program:

Assuming the data state is null or undefined initially. In the case of second program, the useEffect is called because randomFunc was initialised once in the beginning. And that would update the parent state data to Some data!. This would lead to render cycle getting triggered and evaluating randomFunc again and thus changing it. This time it would again trigger the useEffect in child and tries to update the state in parent component. But as the same value Some data! is sent back to the parent state, the parent state ignores that value, thus ending the cycle of rendering again

Upvotes: 2

Related Questions