The text starts here~
Overview
The "Rendered more hooks than during the previous render" error is generated when we conditionally call a hook or return early before all hooks have run. To fix this error, move all hooks to the top level of function components and don't use hooks in conditions.
Here is an example to show how the error occurs.
// App.js
import {useEffect, useState} from 'react';
export default function App() {
const [counter, setCounter] = useState(0);
// ⛔️ Error: Rendered more hooks than during the previous render.
if (counter > 0) {
// 👇️ calling React hook conditionally
useEffect(() => {
console.log('hello world');
});
}
return (
<div>
<button onClick={() => setCounter(counter + 1)}>toggle loading</button>
<h1>Hello world</h1>
</div>
);
}
The problem with the code is that we conditionally call the useEffect
hook.
top-level call
To fix the bug, we have to move the condition inside the hook. Because React hooks can only be called at the top level.
import {useEffect, useState} from 'react';
export default function App() {
const [counter, setCounter] = useState(0);
// ✅ hook is called at top level (not conditionally)
useEffect(() => {
if (counter > 0) {
console.log('hello world');
}
});
return (
<div>
<button onClick={() => setCounter(counter + 1)}>toggle loading</button>
<h1>Hello world</h1>
</div>
);
}
We moved the if
statement inside the useEffect
hook.
This solves the error because we have to make sure that every time the component renders, the React hooks are called in the same order.
This means we are not allowed to use hooks in loops, conditionals or nested functions.
Here is another example to show how the error occurs.
import {useState} from 'react';
export default function App() {
const [counter, setCounter] = useState(0);
// 👇️ this returns before second hook runs if condition is met
if (counter > 0) {
return <h2>Returning early</h2>;
}
// ⛔️ Error because hook is called conditionally
const [color, setColor] = useState('salmon');
return (
<div>
<button onClick={() => setCounter(counter + 1)}>toggle loading</button>
<h1>Hello world</h1>
</div>
);
}
The problem is that the second useState
hook will only be called if the above condition is not met.
on condition
To fix this error, move all hooks to the top level of the component, above any conditions that might return a value.
import {useState} from 'react';
export default function App() {
const [counter, setCounter] = useState(0);
const [color, setColor] = useState('salmon');
// 👇️ condition that may return early must be below all hooks
if (counter > 0) {
return <h2>Returning early</h2>;
}
return (
<div>
<button onClick={() => setCounter(counter + 1)}>toggle loading</button>
<h1>Hello world</h1>
</div>
);
}
We move the second useState
hook to the if
condition that has the potential to return a value.
This is helpful because the hook is now at the top level and has predictable behavior, allowing React to properly save state between calls touseState
anduseEffect
.
As the documentation says:
- Only call Hooks from React function components or custom hooks
- Only use hooks at the top level
- Don't call Hooks in loops, conditionals or nested functions
- Make sure to always use Hook at the top level of your React function and before any return
This helps React preserve the state of the hook across multiple useState
and useEffect
calls.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。