ChatGPT解决这个技术问题 Extra ChatGPT

Why does calling react setState method not mutate the state immediately?

I'm reading Forms section of documentation and just tried this code to demonstrate onChange usage (JSBIN).

var React= require('react');

var ControlledForm= React.createClass({
    getInitialState: function() {
        return {
            value: "initial value"
        };
    },

    handleChange: function(event) {
        console.log(this.state.value);
        this.setState({value: event.target.value});
        console.log(this.state.value);

    },

    render: function() {
        return (
            <input type="text" value={this.state.value} onChange={this.handleChange}/>
        );
    }
});

React.render(
    <ControlledForm/>,
  document.getElementById('mount')
);

When I update the <input/> value in the browser, the second console.log inside the handleChange callback prints the same value as the first console.log, Why I can't see the result of this.setState({value: event.target.value}) in the scope of handleChange callback?

If you're using hooks, take a look at useState set method not reflecting change immediately.
React 18 has introduced automatic batching

M
Michael Parker

From React's documentation:

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value. There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

If you want a function to be executed after the state change occurs, pass it in as a callback.

this.setState({value: event.target.value}, function () {
    console.log(this.state.value);
});

Good answer. The observation that I need to do is be careful to use valueLink. It works good if you not have to format/mask the input.
You might also want to check out componentDidUpdate. It will be called after the state has changed.
Quick question if i may, i see once we pass the function which we need as callback to setState , i was hoping that the func would be executed first before render() is called. But i see the order is setState() -> render() -> setStates' callback() . is this normal? What if we want to control our render based on the stuff we do in callback ? shouldComponentUpdate?
Changing state of a component will always trigger a re-render unless there is behavior in shouldComponentUpdate that specifies otherwise. What exactly are you trying to do in the callback you're passing to setState that you want to occur before the re-render?
...why? Could someone justify this?
Y
Yo Wakita

As mentioned in the React documentation, there is no guarantee of setState being fired synchronously, so your console.log may return the state prior to it updating.

Michael Parker mentions passing a callback within the setState. Another way to handle the logic after state change is via the componentDidUpdate lifecycle method, which is the method recommended in React docs.

Generally we recommend using componentDidUpdate() for such logic instead.

This is particularly useful when there may be successive setStates fired, and you would like to fire the same function after every state change. Rather than adding a callback to each setState, you could place the function inside of the componentDidUpdate, with specific logic inside if necessary.

// example
componentDidUpdate(prevProps, prevState) {
  if (this.state.value > prevState.value) {
    this.foo();  
  }
}

k
kurokiiru

You could try using ES7 async/await. For instance using your example:

handleChange: async function(event) {
    console.log(this.state.value);
    await this.setState({value: event.target.value});
    console.log(this.state.value);
}

How is your answer different from the other high quality answer?
The other answer is with respect to using the callback in setState(). I thought I put this here for those whom a callback use case doesn't apply. For instance, when I faced this problem myself, my use case involved a switch case on the updated state right after setting it. Therefore using async/await was preferred to using a callback.
will this impact performance if I always use await always when I want to update some state and then wait for it to have updated? And if I put multiple await setStates in a chain one below another, will it render after each setState update? or after the last setState update?
y
yangsibai

Watch out the react lifecycle methods!

http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

https://reactjs.org/docs/react-component.html

I worked for several hours to find out that getDerivedStateFromProps will be called after every setState().

😂


R
Ritwik

async-await syntax works perfectly for something like the following...

changeStateFunction = () => {
  // Some Worker..

  this.setState((prevState) => ({
  year: funcHandleYear(),
  month: funcHandleMonth()
}));

goNextMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

goPrevMonth = async () => {
  await this.changeStateFunction();
  const history = createBrowserHistory();
  history.push(`/calendar?year=${this.state.year}&month=${this.state.month}`);
}

D
Dean P

Accessing this.state after calling the setState method is not guaranteed to return the updated status due to the asynchronous nature of setState.

To guarantee an update after calling setState, there are two solutions you may pursue.

Solution 1: As mentioned in one of the above answers, put your code in the componentDidUpdate method

Solution 2: As mentioned in another of the above answers, pass your stuff as a callback

 this.setState({value: myValue}, function () {
    this.functionThatIsExecutedWhenStateIsUpdated();
});

It's important to note that these two solutions are not clearly interchangeable. The one cannot easily solve all the use-cases of the other. As a general rule, if you can, best practice says that solution 1 is preferred. But, there are use-cases where only solution 2 "more effectively" works such as the "update-my-view-and-post-my-data" use case. This use case goes like this:

https://i.stack.imgur.com/hktFa.png

If you dont do either solution, i.e. if you only say this in your code:

addToItemArray = () => { 
     this.setState{{ scheduledItemsArray: newObjectListWithMax}}   
     this.postData();
}

<button className="btn btn-secondary btn-block" onClick={this.addToItemArray}>Add Shedule</button>

... you will post the list excluding the "Delivery to Max" item, because the state wont be updated when you this.postData() (again, because its asynchronous).

If you utilise solution 1, you would make a POST after typing in every character in the Schedule Name textbox!

There are other ways aswell to cater for this use-case but solution 2 best conveys the intent when reading the code.

Given the ubiquitous nature of this use case in virtually every web app, the callback technique explained by Michael's answer is an indispensable piece of code in every developers toolkit.


S
S.Yadav

Sometime this issue occurs with state.
In case of hooks, you should use useEffect hook, As below-

const [fruit, setFruit] = useState('');
 
setFruit('Apple');
useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])

This saved my day, Hope will help you!!!


V
Vishal Bisht

Simply putting - this.setState({data: value}) is asynchronous in nature that means it moves out of the Call Stack and only comes back to the Call Stack unless it is resolved.

Please read about Event Loop to have a clear picture about Asynchronous nature in JS and why it takes time to update -

https://medium.com/front-end-weekly/javascript-event-loop-explained-4cd26af121d4

Hence -

    this.setState({data:value});
    console.log(this.state.data); // will give undefined or unupdated value

as it takes time to update. To achieve the above process -

    this.setState({data:value},function () {
     console.log(this.state.data);
    });

Y
Yilmaz

React bathces different set state calls so that it can determine what is the most optimal strategy for rerendering the website is going to be.

Imagine you have an application where you have a lot of different components. Perhaps, with one button click you are updating the state in multiple components, not just on the current one. In this case, React does not want to just completely isolate and do all those different updates independently.

React wants to figure out if it can stack all these updates together, maybe there is a more optimal way of updating these components so that it is more performant. This is what React is doing behind the scenes. As a result, set state call is asynchronous call.