Yan*_*Tay 8 javascript reactjs react-hooks
给定以下组件,当我按下年龄选择器并将值更改为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$1 (react-dom.development.js:18987)
at batchedUpdates (react-dom.development.js:2210)
at dispatchEvent (react-dom.development.js:4946)
at interactiveUpdates$1 (react-dom.development.js:18974)
at interactiveUpdates (react-dom.development.js:2217)
at dispatchInteractiveEvent (react-dom.development.js:4923)
Run Code Online (Sandbox Code Playgroud)
示例代码如下:
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'));Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>Run Code Online (Sandbox Code Playgroud)
小智 17
我通过更改 React Hooks 的顺序解决了这个问题。
所以我已经改变了代码
function(){
const [loading ,setLoading] = React.useState(false);
if(loading){
return "loading ....."
}
useEffect(()=>{
if(condition) {
doSomething();
}
}, []);
return <div>component</div>
}
Run Code Online (Sandbox Code Playgroud)
到
function(){
const [loading ,setLoading] = React.useState(false);
useEffect(()=>{
if(condition) {
doSomething();
}
}, []);
if(loading){
return "loading ....."
}
return <div>component</div>
}
Run Code Online (Sandbox Code Playgroud)
因此,当加载变为 true 时,useEffect 将不会运行,并且会抛出错误..但是如果我在 useEffect 之后声明加载 JSX 元素,那么它将完美运行。
Yan*_*Tay 15
的问题是,在第一渲染,3个useState钩被调用- name,age和license但年龄改变为值低于16之后,useState为license不再被调用,导致只有第一2个钩子被调用.正如React docs所述:
不要在循环,条件或嵌套函数中调用Hook.相反,始终在React函数的顶层使用Hooks.通过遵循此规则,您可以确保每次组件呈现时都以相同的顺序调用Hook.这就是允许React在多个
useState和useEffect调用之间正确保留Hook状态的原因.
被调用的钩子的顺序很重要,如果我们编写导致钩子不被调用的代码,React将无法将钩子调用与其值匹配.
解决方案是将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'));Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>Run Code Online (Sandbox Code Playgroud)
确保您没有useEffect有条件地运行。
例如,如果您有如下代码:
if(condition) {
useEffect(()=>{
doSomething();
}, []);
}
Run Code Online (Sandbox Code Playgroud)
然后将其更改为
useEffect(()=>{
if(condition) {
doSomething();
}
}, []);
Run Code Online (Sandbox Code Playgroud)
那么错误就不会发生。
所以我也遇到了这个错误,但它与钩子被包裹在条件中无关。相反,这是由于我的键值不正确造成的。
我有一个组件,可以通过拖放将项目从一个列表移动到另一个列表。然而,其中一些项目被锁定,所以我只是删除了这些元素中对我的钩子的引用。
问题是我使用索引作为键,因此当我在顶部拖动一个新元素时,它得到了与锁定元素相同的键,ref 的值被更改,并且 React 抱怨上述错误。
因此,我对遇到此问题的人的回答是 - 检查您是否拥有真正唯一的密钥!
| 归档时间: |
|
| 查看次数: |
6134 次 |
| 最近记录: |