0

I've taken my app to bare minimum to try to understand why it is infinite looping...but I don't get it.

const App = () => {

  console.log("just logging that the app ran!")
  
  const [data, setData] = useState('initial state');
  
  const getAsset = async () => {
  
    console.log("logging that getAsset ran!")

  setData("new state!")
  console.log(data)
}
  
  getAsset();
  
  return (

    <div >
      {data}
    </div>
  );
}

export default App;

Any pointers?

The error message:

react-dom.development.js:14997 Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
elderlyman
  • 500
  • 8
  • 24
  • 1
    Does this answer your question? [How to async await in react render function?](https://stackoverflow.com/questions/53819864/how-to-async-await-in-react-render-function) – Emile Bergeron Aug 12 '21 at 17:52
  • 1
    TL;DR: `setData` triggers a new render, which calls `getAsset` again, and here's the loop! – Emile Bergeron Aug 12 '21 at 17:53
  • 1
    https://stackoverflow.com/questions/55265604/uncaught-invariant-violation-too-many-re-renders-react-limits-the-number-of-re – Jaskaran Deol Aug 12 '21 at 18:01

4 Answers4

2

Just call the getAsset inside useEffect hook. Not sure why the function is made async though. In your case setData causes a re-render and again calls the getAsset function which results in a loop

Working sandbox : https://codesandbox.io/s/react-hooks-example-forked-0rqb9?file=/src/App.js

const App = () => {

  const [data, setData] = useState("initial state");

  useEffect(() => {
    getAsset();
  }, []);

  const getAsset = async () => {
    setData("new state!");
  };

  return <div>{data}</div>;
};

export default App;
joy08
  • 9,004
  • 8
  • 38
  • 73
1

your code call getAsset() every time component render and getAsset setState (setData) and when you change state the component rerender and it call getAsset again and rerender again ............

you need to call it on mount so use useEffect


const App = () => {

  console.log("just logging that the app ran!")
  
  const [data, setData] = useState('initial state');
  
  const getAsset = async () => {
  
    console.log("logging that getAsset ran!")

  setData("new state!")
  console.log(data)
}
 
 useEffect(() => {
getAsset();

},[])

  
  return (

    <div >
      {data}
    </div>
  );
}

export default App;
Omar Khaled
  • 439
  • 1
  • 4
  • 16
1

The problem is that App is getting re-run by React every time the state changes, meaning getAsset being called directly in App without any checks to see if it has run already, will cause a loop.

// Runs when the component is rendered.
const App = () => {
  // ...
  getAsset(); // Sets state, re-rendering app.
  // ...
  return (
    <div >
      {data}
    </div>
  );
}

To fix, check to make sure state is only set once or when the new state would be different so no looping behavior can occur.

SciDev
  • 159
  • 6
0

Your component will re-render on each action performed, re-running the async function again and again. A way to avoid this is using the useEffect hook with a dependency of your choice. This way, the async function will only run when it fulfils a certain condition.

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 08 '23 at 08:36