Reaguj setState nie aktualizuje stanu

91

Więc mam to:

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 to tylko tablica liczb, [1, 5, 9]np. jednak this.state.dealersOverallTotalnie podaje prawidłowej sumy, ale totaltak jest? Ustawiłem nawet limit czasu, aby sprawdzić, czy to rozwiązało problem. jakieś oczywiste czy powinienem wysłać więcej kodu?

Robak
źródło
@Assan cheers !!
Robak
Oprócz tego, co jest powiedziane w odpowiedziach, jawnie rejestrujesz wartość stanu, zanim zadzwonisz setState.
Felix Kling
1
@FelixKling nie, nazywam this.state po ustawieniu. Loguję wcześniej zmienną. Nie?
Robak
Z powodu przekroczenia limitu czasu Twój setStatejest rzeczywiście wykonywany po zalogowaniu stanu. Myślę, że to, co zamierzałeś zrobić podczas debugowania, to umieszczenie console.logczęści w limicie czasu i na setStatezewnątrz.
Fabian Schultz,

Odpowiedzi:

181

setState()jest zwykle asynchroniczna, co oznacza, że ​​w momencie określania console.logstanu nie jest jeszcze aktualizowana. Spróbuj umieścić dziennik w wywołaniu zwrotnym setState()metody. Jest wykonywany po zakończeniu zmiany stanu:

this.setState({ dealersOverallTotal: total }, () => {
  console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
}); 
Fabian Schultz
źródło
1
Oprócz tego OP jawnie rejestruje wartość stanu przed wywołaniem setState.
Felix Kling
To działa również dla mnie, w przeszłości użyłem tego: `this.setState ({someVar: newValue}, function () {console.log (" force update}); 'ale z jakiegoś powodu nie było to niepokojące co więcej, kiedy zaktualizowałem kod, jak opisano powyżej, działa. jakikolwiek pomysł dlaczego?
Jozcar
@Jozcar Powinien również działać, składnia jest nieprawidłowa (brak nawiasów):this.setState({someVar: newValue},function(){ console.log("force update") });
Fabian Schultz
imgur.com/Ku0OjTl Proszę powiedz mi, co mam zrobić, aby pozbyć się tego problemu.
Johncy
To nie działa, jeśli używasz useState haka w komponencie funkcjonalnym. Użyj useEffectzamiast tego, aby uzyskać efekt po renderowaniu.
Hasan Sefa Ozalp
16

setState jest asynchroniczna. Możesz użyć metody wywołania zwrotnego, aby uzyskać zaktualizowany stan.

changeHandler(event) {
    this.setState({ yourName: event.target.value }, () => 
    console.log(this.state.yourName));
 }
Mahesh Joshi
źródło
10

Korzystanie z async / await

async changeHandler(event) {
    await this.setState({ yourName: event.target.value });
    console.log(this.state.yourName);
}
Dev01
źródło
Ja robię to samo. Pracował dla mnie
prodeveloper
8

setState()Operacja asynchroniczna , a tym samym swój console.log()zostanie wykonany przed setState()mutuje wartości i stąd można zobaczyć wynik.

Aby rozwiązać ten problem, zarejestruj wartość w funkcji wywołania zwrotnego setState(), na przykład:

setTimeout(() => {
    this.setState({dealersOverallTotal: total},
    function(){
       console.log(this.state.dealersOverallTotal, 'dealersOverallTotal1');
    });
}, 10)
Shubham Khatri
źródło
JavaScript jest zawsze synchroniczny.
Santosh Singh
1
@santoshsingh masz błędne przekonanie. Wywołania API i przekroczenia limitu czasu są wykonywane asynchronicznie.
Shubham Khatri
Jak wspomniałeś powyżej, javascript jest asynchroniczny - nie jest poprawny. Jest głównie synchroniczny, aw przypadkach asynchroniczny. stackoverflow.com/questions/2035645/…
Santosh Singh
@santoshsingh. Och, to był mój błąd. Nie sformułował poprawnie zdania
Shubham Khatri
bardzo sprytne wykorzystanie wywołania zwrotnego, aby zapewnić aktualizację stanu przed kolejnym wywołaniem!
user1204214
5

W przypadku haczyków należy użyć useEffecthaka.

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

setFruit('Apple');

useEffect(() => {
  console.log('Fruit', fruit);
}, [fruit])
Siraj Alam
źródło
Świetnie, działa z useEffect. Ale dlaczego go potrzebuje?
alex351
useEffectdziała przy każdym ponownym renderowaniu, a jeśli elementy przekazane do tablicy są zmiennymi stanu, zostaną zmienione. Więc kiedy owoc się zmieni i komponent zostanie ponownie wyrenderowany, to useEffect będzie działać.
Siraj Alam
Uruchamiam setFruit i console.log owoce poza useEffect i to się nie zmienia. : /
alex351
3

Setstate reaguje asynchronicznie, więc aby zobaczyć zaktualizowany stan w konsoli, użyj wywołania zwrotnego, jak pokazano poniżej (funkcja Callback zostanie wykonana po aktualizacji setstate)

wprowadź opis obrazu tutaj

Poniższa metoda jest „niezalecana”, ale dla zrozumienia, jeśli zmienisz stan bezpośrednio, możesz zobaczyć zaktualizowany stan w następnej linii. Powtarzam, że to „nie jest zalecane”

wprowadź opis obrazu tutaj

mokesh moha
źródło
DZIĘKUJEMY to jest to, musisz bezpośrednio ustawić zmienną
notacorn
0

Miałem problem z kilkakrotnym ustawieniem stanu reakcji (zawsze używał stanu domyślnego). Po tym problemie z odpowiedzią / githubem zadziałał dla mnie

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

// Do this!
setState(prevState => {
  return {
    ...prevState,
    foo: "def"
  };
});
setState(prevState => {
  return {
    ...prevState,
    bar: 456
  };
});
Arun Gopalpuri
źródło
0

Miałem taką samą sytuację z jakimś zawiłym kodem i nic z istniejących sugestii nie zadziałało.

Mój problem polegał na tym, że setStatedziało się to z funkcji wywołania zwrotnego, wydanej przez jeden z komponentów. I podejrzewam, że połączenie odbywało się synchronicznie, co zapobiegałosetState w ogóle ustawienie stanu.

Po prostu mam coś takiego:

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

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

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

Sposób miałem do „fix” było umieścić doUpdate()w setTimeoutten sposób:

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

Nie jest to idealne rozwiązanie, ale poza tym byłoby to znaczące refaktoryzacja.

zmechanic
źródło