useState() 未在 useEffect() 挂钩内部更新

useState() not updating inside of useEffect() hook

我在更新 useEffect() 内部的 useState() 时遇到问题。我想我可能 运行 陷入无限循环,无论我传入的布尔值如何,useState 都不会更新。它始终显示 false。

export const useAlert = () => {
  const action = useSelector(state => state.edit.action);

  const dispatch = useDispatch();

  const booleanA = true;

  const booleanB = false;

  const [isOverMax, setIsOverMax] = useState(false);
  const reset = () => {
    dispatch(resetEditAction());
  };

  useEffect(() => {
    setIsOverMax(booleanA || booleanB);
  }, isOverMax);

  return [isOverMax, reset];
};

对于更多上下文,booleanAbooleanB 是使用其他代码动态生成的,但即使像上面那样对它们进行硬编码,isOverMax 也只是 false。我永远无法获得真正的价值,即使两个布尔值都被硬编码为 true。

删除 useEffect 的依赖项中的 isOverMax 以避免无限循环

useEffect(() => {
  setIsOverMax(booleanA || booleanB);
}, []);

状态 isOverMax 源自 booleanAbooleanB。因此,只要 booleanAbooleanB 发生变化,isOverMax 就会发生变化。您应该在依赖项数组中反映这一点。

 useEffect(() => {
   setIsOverMax(booleanA || booleanB);
 }, [booleanA, booleanB]);

这是工作示例。只需单击“显示代码片段”,然后单击“运行 代码片段”

const useAlert = () => {
  const [booleanA, setA] = React.useState(true);
  const [booleanB, setB] = React.useState(false);
  const [isOverMax, setIsOverMax] =React. useState(false);

  const reset = () => {
    setA(false);
    setB(false);
  };

  React.useEffect(() => {
    setIsOverMax(booleanA || booleanB);
  }, [booleanA , booleanB]);

  // just for testing
  const toggleA = () => {
    setA((a) => !a);
  }

   return [isOverMax, reset, toggleA];
};

const App = () => {
  const [alert, reset, toggleA]  = useAlert();
  return <div>
    isOverMax={"" + alert}<br/>
    <button onClick={() => toggleA()} >Toggle A</button>
    <button onClick={() => reset()} >Reset </button>
  </div>;
};

ReactDOM.render(<App />, document.getElementById("root"));
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

由于状态 booleanAbooleanB 已经存在,当其中一个状态改变时,它们将触发重新渲染。因此你可以 return 计算 isOverMax

const useAlert = () => {

   // ...
   return [booleanA || booleanB, reset];
}

    const useAlert = () => {
      const [booleanA, setA] = React.useState(true);
      const [booleanB, setB] = React.useState(false);
      const isOverMax = booleanA || booleanB;

      const reset = () => {
        setA(false);
        setB(false);
      };

      // just for testing
      const toggleA = () => {
        setA((a) => !a);
      }

       return [isOverMax, reset, toggleA];
    };

    const App = () => {
      const [alert, reset, toggleA]  = useAlert();
      return <div>
        isOverMax={"" + alert}<br/>
        <button onClick={() => toggleA()} >Toggle A</button>
        <button onClick={() => reset()} >Reset </button>
      </div>;
    };

    ReactDOM.render(<App />, document.getElementById("root"));
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

编辑

Are there any general guidelines for when NOT to use the effect hook so I don't start throwing it in code where it isn't crucial?

不一定,但你应该读过 Rules of Hooks。这些规则告诉您应该怎样做才能防止不可预测的行为。可悲的是,他们没有解释该规则的原因,这个问题是解释这一切的错误地方。因此,如果您还有一个问题,请打开另一个问题。