首页 > 解决方案 > useState() not updating inside of useEffect() hook

问题描述

I'm having a problem updating useState() inside of useEffect(). I think I may be running into an infinite loop and useState isn't updating regardless of the booleans that I pass in. It always shows 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];
};

For more context, booleanA and booleanB are dynamically generated with other code, but even when they are hardcoded like above, isOverMax only ever is false. I can never get a true value, even when both booleans are hardcoded as true.

标签: reactjsreact-reduxreact-hooksstate

解决方案


The state isOverMax is derived from booleanA and booleanB. Thus isOverMax should change whenever booleanA or booleanB is changed. You should reflect this in your dependency array.

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

Here is the working example. Just click "Show code snippet" and then "Run code Snippet"

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>

Since the states booleanA and booleanB already exist, they will trigger a rerender when one of them is changed. Thus you can just return the calculation of 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>

EDIT

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?

Not really, but you should have read Rules of Hooks. The rules tell you what you should do to prevent unpredictable behavior. Sadly they don't explain the reasons for that rule and this question is the wrong place to explain it all. Thus please open another question if you still have one.


推荐阅读