我已经使用React钩子遇到了Invariant violation: rendered fewer hooks than expected
问题。从其他答案中可以明显看出,不应有条件地调用钩子(Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement in React Hooks)。
导致应用崩溃的情况:
const MyComponent = (item) => {
const [itemState, setState] = useState(true);
if (!item) {
return null;
}
const [anotherState, setAnotherState] = useState(true);
return (<div>{item.name}</div>)
}
作为尝试,我试图通过在调用钩子之前移动支票来修复它,例如:
const MyComponent = (item) => {
if (!item) {
return null;
}
const [itemState, setState] = useState(true);
const [anotherState, setAnotherState] = useState(true);
return (<div>{item.name}</div>)
}
这似乎有效,并且从未崩溃。
我决定安装eslint-plugin-react-hooks
以防止将来出现类似情况。现在它以React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?
所以我的问题是:我应该始终执行返回after
的所有钩子吗?例如:
const MyComponent = (item) => {
const [itemState, setState] = useState(true);
const [anotherState, setAnotherState] = useState(true);
if (!item) {
return null;
}
return (<div>{item.name}</div>)
}
如果是,为什么然后如果我先返回between
和第二个钩子就会崩溃,而如果我返回before
所有的钩子却不会崩溃呢?
答案 0 :(得分:0)
声明您在顶部无条件地使用useState
-
const MyComponent = ({item}) => {
const [itemState, setState] = useState(true);
const [anotherState, setAnotherState] = useState(true);
const [localItem, setLocalItem] = useState(item);
return localItem == null ? <></> : <div>{item.name}</div>;
};
在此处查找规则-https://reactjs.org/docs/hooks-overview.html#rules-of-hooks
答案 1 :(得分:0)
如果在提前返回之前或之后移动所有钩子,则每个渲染上始终具有相同数量的钩子(无或2个)。如果您先放一个钩子,然后再放一个钩子,那么您就不放了,当它返回得早时,您将有一个钩子,而当您不放钩子时,将有2个钩子。
提早返回后放置useState会使linter感到困惑,但这也会破坏您的状态。当您提早返回时,此状态将重置,而在下次渲染时则不重置。
在以下示例中,将一个点添加到“ Hello World”中,当您关闭然后再打开时,所有点都消失了。在之前之前定义setState可以让您保持满意。
const { useState } = React;
function App({ wut }) {
const [show, setShow] = useState(true);
return (
<div>
<button onClick={() => setShow(s => !s)}>
toggle
</button>
<MyComponent item={show} />
</div>
);
}
const MyComponent = ({ item }) => {
if (!item) {
return <div>no item</div>;
}
const [itemState, setItemState] = useState('Hello World');
return (
<div>
{itemState}
<button onClick={() => setItemState(s => s + '.')}>
Add .
</button>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>