Oto problem: próbuję wywołać 2 funkcje jednym kliknięciem przycisku. Obie funkcje aktualizują stan (używam haka useState). Pierwsza funkcja poprawnie aktualizuje wartość 1 do „nowej 1”, ale po 1 s (setTimeout) uruchamia się druga funkcja i zmienia wartość 2 na „nową 2” ALE! Ustawia wartość 1 z powrotem na „1”. Dlaczego to się dzieje? Z góry dziękuję!
import React, { useState } from "react";
const Test = () => {
const [state, setState] = useState({
value1: "1",
value2: "2"
});
const changeValue1 = () => {
setState({ ...state, value1: "new 1" });
};
const changeValue2 = () => {
setState({ ...state, value2: "new 2" });
};
return (
<>
<button
onClick={() => {
changeValue1();
setTimeout(changeValue2, 1000);
}}
>
CHANGE BOTH
</button>
<h1>{state.value1}</h1>
<h1>{state.value2}</h1>
</>
);
};
export default Test;
javascript
reactjs
react-hooks
Bartek
źródło
źródło
changeValue2
?useState
lub użycieuseReducer
.const [state, ...]
, a następnie odnosząc się do niego w seterie ... Cały czas będzie używać tego samego stanu.useState
wywołań, po jednym dla każdej „zmiennej”.Odpowiedzi:
Witamy w zamknięciu piekła . Ten problem występuje, ponieważ po każdym
setState
wywołaniustate
otrzymuje nowe odwołanie do pamięci, ale funkcjechangeValue1
ichangeValue2
, z powodu zamknięcia, zachowują stare początkowestate
odwołanie.Rozwiązaniem zapewniającym
setState
odchangeValue1
ichangeValue2
uzyskanie najnowszego stanu jest użycie wywołania zwrotnego (posiadającego poprzedni stan jako parametr):Szerszą dyskusję na temat tego problemu zamknięcia można znaleźć tutaj i tutaj .
źródło
Twoje funkcje powinny wyglądać tak:
Dzięki temu upewnisz się, że nie brakuje żadnej istniejącej właściwości w bieżącym stanie, używając poprzedniego stanu po uruchomieniu akcji. W ten sposób unikasz również zarządzania zamknięciami.
źródło
Po
changeValue2
wywołaniu stan początkowy jest utrzymywany, więc stan wraca do stanu początkowego, a następnievalue2
zapisywana jest właściwość.Następnym razem
changeValue2
wywoływany jest stan{value1: "1", value2: "new 2"}
, więcvalue1
właściwość zostaje nadpisana.Potrzebujesz
setState
parametru strzałki dla parametru.źródło
Co się dzieje jest to, że zarówno
changeValue1
ichangeValue2
zobaczyć stan z tynku zostały stworzone w , więc gdy składnik uczynić po raz pierwszy te 2 funkcje patrz:Po kliknięciu przycisku
changeValue1
wywoływany jest pierwszy i zmienia stan{value1: "new1", value2: "2"}
zgodnie z oczekiwaniami.Teraz, po 1 sekundzie,
changeValue2
jest wywoływana, ale ta funkcja nadal widzi stan początkowy ({value1; "1", value2: "2"}
), więc kiedy ta funkcja aktualizuje stan w ten sposób:setState({ ...state, value2: "new 2" });
skończyć się zobaczyć:
{value1; "1", value2: "new2"}
.źródło
źródło