javascript 未捕获的错误:呈现的钩子比预期的少。这可能是 React Hooks 中意外的提前返回语句导致的
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/53472795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement in React Hooks
提问by Yangshun Tay
Given the following component, when I press down on the age selector and change the value to 15, such that I render a form without the driver license field, I get the error:
给定以下组件,当我按下年龄选择器并将值更改为 15,以便呈现没有驾驶执照字段的表单时,我收到错误消息:
Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement.
at invariant (react-dom.development.js:55)
at finishHooks (react-dom.development.js:11581)
at updateFunctionComponent (react-dom.development.js:14262)
at beginWork (react-dom.development.js:15103)
at performUnitOfWork (react-dom.development.js:17817)
at workLoop (react-dom.development.js:17857)
at HTMLUnknownElement.callCallback (react-dom.development.js:149)
at Object.invokeGuardedCallbackDev (react-dom.development.js:199)
at invokeGuardedCallback (react-dom.development.js:256)
at replayUnitOfWork (react-dom.development.js:17113)
at renderRoot (react-dom.development.js:17957)
at performWorkOnRoot (react-dom.development.js:18808)
at performWork (react-dom.development.js:18716)
at flushInteractiveUpdates (react-dom.development.js:18987)
at batchedUpdates (react-dom.development.js:2210)
at dispatchEvent (react-dom.development.js:4946)
at interactiveUpdates (react-dom.development.js:18974)
at interactiveUpdates (react-dom.development.js:2217)
at dispatchInteractiveEvent (react-dom.development.js:4923)
Example code below:
示例代码如下:
const {useState} = React;
function App() {
const [name, setName] = useState('Mary');
const [age, setAge] = useState(16);
if (age < 16) {
return (
<div>
Name:{' '}
<input
value={name}
onChange={e => {
setName(e.target.value);
}}
/>
<br />
Age:{' '}
<input
value={age}
type="number"
onChange={e => {
setAge(+e.target.value);
}}
/>
</div>
);
}
const [license, setLicense] = useState('A123456');
return (
<div>
Name:{' '}
<input
value={name}
onChange={e => {
setName(e.target.value);
}}
/>
<br />
Age:{' '}
<input
value={age}
type="number"
onChange={e => {
setAge(+e.target.value);
}}
/>
<br />
Driver License:{' '}
<input
value={license}
onChange={e => {
setLicense(e.target.value);
}}
/>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
回答by Yangshun Tay
The problem is that in the first render, 3 useStatehooks were invoked - name, ageand licensebut after the age is changed to a value below 16, the useStatefor licenseis no longer invoked, resulting in only the first 2 hooks being invoked. As the React docs state:
的问题是,在第一渲染,3个useState钩被调用- name,age和license但年龄变更后的值低于16时,useState为license不再被调用,导致只有第一2个钩子被调用。正如React 文档所述:
Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That's what allows React to correctly preserve the state of Hooks between multiple
useStateanduseEffectcalls.
不要在循环、条件或嵌套函数中调用 Hook。相反,始终在 React 函数的顶层使用 Hook。通过遵循此规则,您可以确保每次渲染组件时都以相同的顺序调用 Hook。这就是允许 React 在多次调用
useState和useEffect调用之间正确保留 Hook 状态的原因。
The order of the hooks being called is important, and if we write code that causes hooks to not be called, React will not be able to match the hook call with its values.
调用钩子的顺序很重要,如果我们编写的代码导致钩子不被调用,React 将无法将钩子调用与其值匹配。
The solution is to move the licensehook up to the top of the function so that it gets called regardless whether it is needed or not.
解决方案是将license钩子移动到函数的顶部,以便无论是否需要它都会被调用。
const {useState} = React;
function App() {
const [name, setName] = useState('Mary');
const [age, setAge] = useState(16);
const [license, setLicense] = useState('A123456');
return (
<div>
Name:{' '}
<input
value={name}
onChange={e => {
setName(e.target.value);
}}
/>
<br />
Age:{' '}
<input
value={age}
type="number"
onChange={e => {
setAge(+e.target.value);
}}
/>
{age >= 16 && <span>
<br />
Driver License:{' '}
<input
value={license}
onChange={e => {
setLicense(e.target.value);
}}
/></span>
}
</div>
);
}
ReactDOM.render(<App />, document.querySelector('#app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
回答by Jeff Tian
Make sure that you didn't run useEffectconditionally.
确保您没有useEffect有条件地运行。
For example, if you have some code like the following:
例如,如果您有如下代码:
if(condition) {
useEffect(()=>{
doSomething();
}, []);
}
Then change it to
然后将其更改为
useEffect(()=>{
if(condition) {
doSomething();
}
}, []);
Then the error would not happen.
那么错误就不会发生。

