React - how to fix too many re-renders (infinite loop) error while updating useState with an object?
Hello!
Recently I was looking for a solution on how to update an object inside useState
and got this error: "Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop."
Full stacktrace:
Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
at renderWithHooks (react-dom.development.js:14997)
at mountIndeterminateComponent (react-dom.development.js:17811)
at beginWork (react-dom.development.js:19049)
at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
at invokeGuardedCallback (react-dom.development.js:4056)
at beginWork$1 (react-dom.development.js:23964)
at performUnitOfWork (react-dom.development.js:22776)
at workLoopSync (react-dom.development.js:22707)
at renderRootSync (react-dom.development.js:22670)
at performSyncWorkOnRoot (react-dom.development.js:22293)
at scheduleUpdateOnFiber (react-dom.development.js:21881)
at updateContainer (react-dom.development.js:25482)
at react-dom.development.js:26021
at unbatchedUpdates (react-dom.development.js:22431)
at legacyRenderSubtreeIntoContainer (react-dom.development.js:26020)
at Object.render (react-dom.development.js:26103)
at Module.<anonymous> (index.js:7)
at Module../src/index.js (index.js:18)
at __webpack_require__ (bootstrap:856)
at fn (bootstrap:150)
at Object.1 (reportWebVitals.js:14)
at __webpack_require__ (bootstrap:856)
at checkDeferredModules (bootstrap:45)
at Array.webpackJsonpCallback [as push] (bootstrap:32)
at main.chunk.js:1
Code that causes the error:
import React from 'react';
const App = () => {
const [exampleState, setExampleState] = React.useState({ a: '1' });
setExampleState({ b: '2' });
return <div>{Object.keys(exampleState)}</div>;
};
export default App;
Does anyone know how to fix this?
Here is the solution which I found recently:
First of all, we shouldn't call the setter directly in the component, we should execute it in any action (event, effect, timeout) otherwise it leads to errors.
To prevent React from re-rendering our component too many times (infinite loop), we have to wrap our code e.g with event handling function or with useEffect
hook - to execute our code only once (at App component mount).
Runnable example:
// ONLINE-RUNNER:browser;
// Note: Uncomment import lines while working with JSX Compiler.
// import React from 'react';
// import ReactDOM from 'react-dom';
const App = () => {
const [exampleState, setExampleState] = React.useState({ a: '1' });
React.useEffect(() => {
setExampleState({ b: '2' });
}, []);
return <div>{Object.keys(exampleState)}</div>;
};
const root = document.querySelector('#root');
ReactDOM.render(<App />, root );
Below in related posts, you can find more runnable solutions for the problem.