简体   繁体   中英

Component state change with React Hook setSomeSetting is one step behind

I'm trying to use React Hooks to manage state for a simple text input field and a submit input button. The input field is continuously validated (right now just checking if length >= 1) and the goal is for the state object's 'isOrdered' key to have a value of TRUE when the submit button is clicked and the input is valid.

I've expanded the argument to setMuffinSettings to explicitly return an object and have confirmed that this returned object has isOrdered: true. So the issue has something to do with the setMuffinSettings itself, not an incorrect object being passed to setMuffinSettings.

I've also looked at the two other StackOverflow questions that have to do with React Hooks (specifically hooks) and being 'one step behind.' Neither of these questions' solutions was able to resolve my problem.

React hook and settings variable initialization:

  const [muffinSettings, setMuffinSettings] = useState({
    isInStock: false,
    isOrdered: false,
  });

Submit button event handler:

  const handleMuffinOrder = () => {
    console.log(muffinSettings); // BEFORE: isOrdered is correctly false
    if (muffinSettings.isInStock) {
      console.log('reached'); // this is printed so it's not an issue with isInStock
      setMuffinSettings(prev => ({ ...prev, isOrdered: true }));
    }
    console.log(muffinSettings); // AFTER: isOrdered is incorrectly still false
  }

Submit button:

    return (
      <SubmitOrderButton>
        text="Submit your muffin order"
        // onButtonClick={handleMuffinOrder}
        onButtonClick={() => handleMuffinOrder()}
        // the 2 lines above give me the same error
      />
    );

I expect muffinSettings.isOrdered to be FALSE before the setMuffinSettings call, and TRUE afterwards, provided that muffinSettings.isInStock is TRUE (which it is).

With the code I have right now, muffinSettings is one step behind. In the code snippet for handleMuffinOrder below, I include the console output that's printed the first time you click the button. The second time you click it, however, the value for isOrdered BEFORE is already set to TRUE. So it seems like the value for isOrdered is changed 'between' the first and second button-clicks.

I believe this is not a duplicate of the suggested 'setState doesn't update state immediately' question as we are using React Hooks here, which have only been available since React 16.8, and not the 'older' React state system. According to the React docs, the only argument setMuffinSettings would accept is the new state ie the new object; it would not take a callback as the above suggested question's answer recommends.

Even in hooks, the fundamental implementation of setState remains the same. It is still asynchronous.

Quoting again from the docs :

State Updates May Be Asynchronous. You should not rely on their values for calculating the next state.

It isn't one step behind as such, it's more subtle than that - for performance reasons, state updates are batched and happen asynchonously. If you need to do something after a state changes, then useEffect is your friend.

 const [isInStock, setIsInState] = useState(true);
  const [isOrdered, setIsOrdered] = useState(false);

  const handleMuffinOrder = () => {
    if (isInStock) {
      setIsOrdered(true);
    }
  };
  console.log(isInStock, isOrdered);
  return <button onClick={() => handleMuffinOrder()}> Click Me </button>;
};

This is the easiest way with such a simple component. I tested in CodeSandbox and it changes the state of is ordered to true

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