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?



@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');
}); 

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));
 }

10

Korzystanie z async / await

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

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)

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])

Ś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


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
  };
});

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.