共计 2039 个字符,预计需要花费 6 分钟才能阅读完成。
注释从这开始~
总览
当咱们有条件地调用一个钩子或在所有钩子运行之前提前返回时,会产生 ”Rendered more hooks than during the previous render” 谬误。为了解决该谬误,将所有的钩子移到函数组件的顶层,以及不要在条件中应用钩子。
这里有个示例用来展现谬误是如何产生的。
// 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>
);
}
代码的问题在于,咱们有条件地调用了 useEffect
钩子。
顶层调用
为了解决该谬误,咱们必须将条件移到钩子外部。因为 React 钩子只能在顶层调用。
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>
);
}
咱们将 if
语句挪动到了 useEffect
钩子外部。
这就解决了谬误,因为咱们必须确保每次组件渲染时,React 钩子都以雷同的程序被调用。
这意味着咱们不容许在循环、条件或嵌套函数中应用钩子。
这里有另外一个示例用来展现谬误是如何产生的。
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>
);
}
问题在于,第二个 useState
钩子只有在下面的条件没有满足时才会被调用。
条件之上
为了解决这个谬误,把所有的钩子移到组件的顶层,在任何可能返回值的条件之上。
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>
);
}
咱们把第二个 useState
钩子挪动到有可能返回一个值的 if
条件下面。
这是很有帮忙的,因为钩子当初在顶层,并且有可预测的行为,容许 React 在调用
useState
和useEffect
之间正确地保留状态。
就像文档中所说的那样:
- 只从 React 函数组件或自定义钩子中调用 Hook
- 只在最顶层应用 Hook
- 不要在循环,条件或嵌套函数中调用 Hook
- 确保总是在你的 React 函数的最顶层以及任何 return 之前应用 Hook
这有助于 React 在多个 useState
和useEffect
调用之间保留钩子的状态。
正文完