ChatGPT解决这个技术问题 Extra ChatGPT

React setState not updating state

So I have this:

let total = newDealersDeckTotal.reduce(function(a, b) {
  return a + b;
},
0);

console.log(total, 'tittal'); //outputs correct total
setTimeout(() => {
  this.setState({ dealersOverallTotal: total });
}, 10);

console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1'); //outputs incorrect total

newDealersDeckTotal is just an array of numbers [1, 5, 9] e.g. however this.state.dealersOverallTotal does not give the correct total but total does? I even put in a timeout delay to see if this solved the problem. any obvious or should I post more code?

Besides what is said in the answers, you are explicitly logging the value of the state, before you are calling setState.
@FelixKling no I'm calling this.state after I set it. I am logging a variable before. no?
Because of the timeout your setState is indeed executed after you log the state. I think what you meant to do in debugging was putting the console.log part inside the timeout, and the setState outside.
@FabianSchultz can you explain one thing I'm not getting then. consider this code: if(this.state.playersOverallTotal > 21){ console.log('bust'); this.setState({playerBusted: true}); } when it gets to over 21, the log fires but the state does not change and then only changes once the number increments again. e.g. if it got to 24 it would not set the state but then if it got to 28 for example it would

F
Fabian Schultz

setState() is usually asynchronous, which means that at the time you console.log the state, it's not updated yet. Try putting the log in the callback of the setState() method. It is executed after the state change is complete:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 

In addition to that, the OP explicitly logs the state value before they call setState.
This works for me as well, in the past I have used this: `this.setState({someVar: newValue},function(){ console.log("force update}); ' but for some reason it was't worring any more, when I updated the code as describe above it work. any idea why?
@Jozcar Should work also, syntax wasn't right (missing parentheses): this.setState({someVar: newValue},function(){ console.log("force update") });
imgur.com/Ku0OjTl Please tell me what should i do to get rid of this problem.
I had completely forgot the fact that it's async call and did all possible code changes except for this one and here you saved my brain from burning out. thanks
S
Siraj Alam

In case of hooks, you should use useEffect hook.

const [fruit, setFruit] = useState('');

setFruit('Apple');

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

Great, it works with useEffect. But why does it need one?
useEffect runs on every re-render, and if the items passed into the array are state variable sand changed. So when the fruit changed and component re-renders, that useEffect will run.
I run setFruit and console.log fruit outside of useEffect, and it does not change. :/
M
Mahesh Joshi

setState is asynchronous. You can use callback method to get updated state.

changeHandler(event) {
    this.setState({ yourName: event.target.value }, () => 
    console.log(this.state.yourName));
 }

D
Dev01

Using async/await

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

setState doesn't return a promise, so I don't expect this to work.
M
Mokesh S

The setState is asynchronous in react, so to see the updated state in console use the callback as shown below (Callback function will execute after the setState update)

this.setState({ email: 'test@example.com' }, () => {
   console.log(this.state.email)
)}

THANK YOU this is it, you have to directly set the variable
M
Massimiliano Kraus

The setState() operation is asynchronous and hence your console.log() will be executed before the setState() mutates the values and hence you see the result.

To solve it, log the value in the callback function of setState(), like:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)

JavaScript is always synchronous.
@santoshsingh you have a misconception. API calls, timeouts all happen asynchronously.
As you mentioned above that javascript is asynchronous --- it's not correct. Its mainly synchronous and for cases it's asynchronous. stackoverflow.com/questions/2035645/…
@santoshsingh. Ohh that was a mistake on my part. Didn't form the sentence correctly
very clever use of the callback to ensure the state is updated before the subsequent call!
A
Arun Gopalpuri

I had an issue when setting react state multiple times (it always used default state). Following this react/github issue worked for me

const [state, setState] = useState({
  foo: "abc",
  bar: 123
});

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});

setting the state like this fixed it for me
z
zmechanic

I had the same situation with some convoluted code, and nothing from the existing suggestions worked for me.

My problem was that setState was happening from callback func, issued by one of the components. And my suspicious is that the call was occurring synchronously, which prevented setState from setting state at all.

Simply put I have something like this:

render() {
    <Control
        ref={_ => this.control = _}
        onChange={this.handleChange}
        onUpdated={this.handleUpdate} />
}

handleChange() {
    this.control.doUpdate();
}

handleUpdate() {
    this.setState({...});
}

The way I had to "fix" it was to put doUpdate() into setTimeout like this:

handleChange() {
    setTimeout(() => { this.control.doUpdate(); }, 10);
}

Not ideal, but otherwise it would be a significant refactoring.


This solved my issue, but I put the setState() inside of the setTimeout() instead. Thank you!
Thanks a lot man. You just saved me from even more debugging.
G
Gus T Butt

As well as noting the asynchronous nature of setState, be aware that you may have competing event handlers, one doing the state change you want and the other immediately undoing it again. For example onClick on a component whose parent also handles the onClick. Check by adding trace. Prevent this by using e.stopPropagation.


Thanks for leaving this. Your comment pointed me in the right direction. I found the problematic code being updated in a conflicting event, then in that spot I used prevState callback to set new state as mentioned above by @Arun Gopalpuri ``` this.setState(prevState=>{ return {...prevState, newProperty }}); ```
D
Dani Alcalà

If you work with funcions you need to use UseEffect to deal with setState's asynchrony (you can't use the callback as you did when working with classes). An example:

import { useState, useEffect } from "react";

export default function App() {
 const [animal, setAnimal] = useState(null);

 function changeAnimal(newAnimal) {
  setAnimal(newAnimal);
  // here 'animal' is not what you would expect
  console.log("1", animal);
 }

 useEffect(() => {
  if (animal) {
   console.log("2", animal);
  }
 }, [animal]);

 return (
  <div className="App">
  <button onClick={() => changeAnimal("dog")} />
 </div>
 );
}

First console.log returns null, and the second one returns 'dog'


P
Pravin Ghorle

just add componentDidUpdate(){} method in your code, and it will work. you can check the life cycle of react native here:

https://images.app.goo.gl/BVRAi4ea2P4LchqJ8