简体   繁体   中英

Weird state object corruption when using functional update with the useState hook

Consider this trivial example where a function is used to update a useState object:

App.tsx

import { useState } from 'react';

export default function App() {
  const [state, setState] = useState({
    id: 0,
  });
  const update = () => {
    setState(prev => {
      const id = Date.now();
      console.log('previous id:', prev.id, 'new id:', id);
      return {
        id,
      };
    });

    // const id = Date.now();
    // console.log("previous id:", state.id, "new id:", id);
    // setState({ id });
  };

  return (
    <div>
      <div>state: {JSON.stringify(state)}</div>
      <button onClick={update}>Update</button>
    </div>
  );
}

Put this in a standard create-react-app typescript template (with React 17.0.2), and run the app in dev mode. Keep clicking the update button and observe the console. Soon enough one would run into a discrepancy between the intended state and the actual state, eg

previous id: 1636301326090 new id: 1636301326260
previous id: 1636301326260 new id: 1636301326440
previous id: 1636301326440 new id: 1636301326611
previous id: 1636301326612 new id: 1636301326804  // What???
previous id: 1636301326804 new id: 1636301326997

In the console log above, the id: 1636301326612 state came out of nowhere as the state being set was id: 1636301326611 .

Stranger still I cannot reproduce this when the app is built for production. Also, if I forgo functional update and just pass an object to setState as in the commented-out code (infeasible in my actual non-toy code due to atomicity requirement), the issue also doesn't seem to be present.

I'm at a complete loss. Am I using setState wrong somehow?

I can provide a complete example repo if necessary.

Perhaps this is due to the fact that the setState is called twice in strict mode in development.
Setting the state value does not depend on the previous value, but on the time. This is a side effect.

Related links
https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects https://github.com/facebook/react/issues/12856

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM