反应 useEffect 警告以放置缺少的依赖项。但是钩子中的依赖值发生了变化

Posted

技术标签:

【中文标题】反应 useEffect 警告以放置缺少的依赖项。但是钩子中的依赖值发生了变化【英文标题】:React useEffect warning to put missing dependency. But dependency value changes in the hook 【发布时间】:2020-11-13 03:35:43 【问题描述】:

我想在 step 的值改变时改变 formStepTouched 的值,所以我使用了 useEffect。但是 useEffect 会抛出一个警告,指出它缺少对 formStepTouched 的依赖。因为那是正在改变的值,把它放在依赖数组中会导致无限调用。

 const [step, setStep] = useState(0);
 const [formStepTouched, setFormStepTouched] = useState(
    Array(childrenArray.length)
      .fill(false)
      .map((_, idx) => idx === 0)
 )

 useEffect(() => 
    const newFormStepTouched = [...formStepTouched];
    newFormStepTouched[step] = true;
    setFormStepTouched(newFormStepTouched);
  , [step]);

请参考下面的代码框链接: https://codesandbox.io/s/brave-gould-ymjt0?file=/src/App.js

正如您所见,演示运行良好,但显示了一条错误消息。如果添加了依赖,useEffect 将被无限调用。

如何摆脱错误信息。

【问题讨论】:

上面的sn-p中useState是否缺少右括号? 能否请您在代码框内提供一个示例? 是的,右括号丢失,已修复。添加了与代码框演示的链接。 【参考方案1】:
   useEffect(() => 
    setFormStepTouched(prevState =>  
      const newFormStepTouched = [...prevState]
      newFormStepTouched[step] = true
      return newFormStepTouched
    );
  , [step]);

linter 告诉你有一个外部依赖可能会改变,你可以阅读更多here

【讨论】:

这会改变 formStepTouched 并且不会重新渲染组件。【参考方案2】:

您可以将回调传递给状态设置器:

const  useEffect, useState  = React;

const App = () => 
  const [step, setStep] = useState(0);
  const [formStepTouched, setFormStepTouched] = useState(
    Array(5)
      .fill(false)
      .map((_, idx) => idx === 0)
  );

  useEffect(() => 
    //pass a callback to state setter
    setFormStepTouched((formStepTouched) => 
      if (formStepTouched[step] === true) 
        //nothing to change
        return formStepTouched;
      
      return formStepTouched.map((s, i) =>
        i === step ? true : s
      );
    );
  , [step]);

  return (
    <div>
      <button onClick=() => setStep(step + 1)>
        nex step
      </button>
      <div>
        <pre>
          JSON.stringify(formStepTouched, undefined, 2)
        </pre>
      </div>
    </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>

【讨论】:

我可能错了,但这不会改变状态。如果你传递一个回调,像这样改变状态是否可以? @dracarys 如果您在沙箱中尝试,现在删除的带有prevState[step] = true 的答案将改变状态,您会看到 steps 数组比当前 step 落后一步,因为该效果不会导致组件重新使成为。数组映射创建一个新数组并且不会发生变异。你也可以const copy = [...current]; copy[step]=true;return copy; 感谢您的解释,但我不确定我是否完全理解。 formStepTouched 仍然指向内存中的相同位置,对吗?还是因为它是在参数中传递的,React 内部会处理它并传递一个指向不同位置的参数? @dracarys 你认为我在哪一行改变了formStepTouched 我刚刚又浏览了一遍你的代码,我不认为你是,我之前弄糊涂了。感谢您的帮助。

以上是关于反应 useEffect 警告以放置缺少的依赖项。但是钩子中的依赖值发生了变化的主要内容,如果未能解决你的问题,请参考以下文章

如何绕过 React 的 useEffect() “缺少依赖项”警告?

我收到一个奇怪的警告“React hook useEffect 缺少依赖项”

如何解决此警告:“React Hook useEffect 缺少依赖项:'history'”?

useEffect 在自定义钩子中使用 ref 缺少依赖项警告

React Hook useEffect缺少依赖项。包括它们或删除依赖项数组

React Hook useEffect 缺少依赖项:'props'