React Hooks 的早期返回问题 [英] Early return issue with React Hooks

查看:54
本文介绍了React Hooks 的早期返回问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了不变性违规:使用 React 钩子呈现的钩子比预期少 问题.从其他答案中,很明显不应有条件地调用钩子(未捕获的错误:呈现的钩子比预期的少.这可能是由于 React Hooks 中的一个意外的提前返回语句造成的.

导致应用崩溃的案例:

const MyComponent = (item) =>{const [itemState, setState] = useState(true);如果(!项目){返回空;}const [anotherState, setAnotherState] = useState(true);返回(

{item.name}

)}

作为尝试,我尝试通过在调用钩子之前移动检查来修复它,例如:

const MyComponent = (item) =>{如果(!项目){返回空;}const [itemState, setState] = useState(true);const [anotherState, setAnotherState] = useState(true);返回(

{item.name}

)}

这似乎有效,而且永远不会崩溃.我决定安装 eslint-plugin-react-hooks 以防止将来发生类似情况.现在它用 React Hook 发出警告,useState"被有条件地调用.在每个组件渲染中,必须以完全相同的顺序调用 React Hooks.你是不是在提前返回后不小心调用了 React Hook?

所以我的问题是:我应该总是在所有钩子都运行之后 after 返回吗?例如:

const MyComponent = (item) =>{const [itemState, setState] = useState(true);const [anotherState, setAnotherState] = useState(true);如果(!项目){返回空;}返回(

{item.name}

)}

如果是,为什么如果我返回 between 第一个和第二个钩子它会崩溃,如果我返回 before 所有钩子不会崩溃?

解决方案

如果在提前返回之前或之后移动所有钩子,那么每次渲染时总是有相同数量的钩子(无或 2 个).如果你在前面放一个,然后在后面放一个,那么当它早点返回时,你有一个钩子,当你没有时,你有两个钩子.

在提前返回之后放置 useState 会混淆 linter,但它也会破坏您的状态.当您提前返回时,状态会重置,而在下一次渲染时不会重置.

在下面的示例中,一个点被添加到Hello World",当您关闭和打开时,所有的点都消失了.在早期返回之前定义 setState 将使您保留这些点.

const { useState } = React;功能应用程序({ wut }){const [show, setShow] = useState(true);返回 (<div><button onClick={() =>setShow(s => !s)}>切换<MyComponent item={show}/>

);}const MyComponent = ({ item }) =>{如果(!项目){返回<div>no item</div>;}const [itemState, setItemState] = useState('Hello World');返回 (<div>{项目状态}<button onClick={() =>setItemState(s => s + '.')}>添加 .

);};ReactDOM.render(, 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>

I have faced the Invariant violation: rendered fewer hooks than expected issue using react hooks. From the other answers, it is clear that hooks should not be called conditionally (Uncaught Error: Rendered fewer hooks than expected. This may be caused by an accidental early return statement in React Hooks).

The case which caused the app crash:

const MyComponent = (item) => {
    const [itemState, setState] = useState(true);

    if (!item) {
        return null;
    }

    const [anotherState, setAnotherState] = useState(true);

    return (<div>{item.name}</div>)
}

As an attempt, I tried to fix it by moving the check prior to calling the hooks, e.g:

const MyComponent = (item) => {

    if (!item) {
        return null;
    }

    const [itemState, setState] = useState(true);
    const [anotherState, setAnotherState] = useState(true);

    return (<div>{item.name}</div>)
}

This seems to work and it never crashes. I decided to install eslint-plugin-react-hooks to prevent similar cases in the future. Now it warns with a 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?

So my question is: should I always do the return after all the hooks are run? e.g:

const MyComponent = (item) => {

    const [itemState, setState] = useState(true);
    const [anotherState, setAnotherState] = useState(true);

    if (!item) {
        return null;
    }

    return (<div>{item.name}</div>)
}

If yes, why then it crashes if I return between first and seconds hooks and doesn't crash if I return before all the hooks?

解决方案

If you move all the hooks before or after the early return then you always have the same amount of hooks (none or 2) on every render. If you put one before and one after then you don't, when it returns early you have one hook and when you don't you have 2 hooks.

Putting the useState after the early return confuses the linter but it also kind of breaks your state. The state is reset when you early return and on next render don't.

In the following example a dot is added to "Hello World", when you toggle off and on then all the dots are gone. Defining setState before the early return will have you keep the dots.

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>

这篇关于React Hooks 的早期返回问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆