Chcę, aby moja funkcja aysnc reagowała na zmianę stanu, aby mogła zakończyć się po zmianie stanu. Odkryłem, że nie reaguje na zmianę stanu. W podanym przykładzie jestem...

1
ablaszkiewicz1 23 czerwiec 2021, 13:18

4 odpowiedzi

Najlepsza odpowiedź

Zmienne stanu nigdy nie zmieniają swoich wartości. (Pamiętaj, że możesz, mieć i powinieneś zadeklarować je za pomocą const, ponieważ się nie zmieniają).

Kolejne wywołania funkcji składowej otrzymają nową zmienną stanu o tej samej nazwie i innej wartości.

Twoja funkcja testFunction została zamknięta na starej zmiennej stanu.


Podejrzewam, że możesz to rozwiązać za pomocą odniesienia:

const [testVariable, setTestVariable] = useState(false);
const reference = useRef();
reference.current = testVariable;

… a następnie przetestuj swoją funkcję na wartość reference.current zamiast testVariable.


Wygląda to jednak jak Problem XY, gdzie prawdziwym rozwiązaniem jest „Użyj wartości zwracanej z funkcji, którą przekazujesz do useEffect, aby zatrzymać to, co chcesz zatrzymać” (i użyj testVariable jako zależności useEffect).

2
Quentin 23 czerwiec 2021, 10:22

Aktualizacja stanu w reakcji jest asynchroniczna oznacza, że ​​Twój stan zostanie zmieniony w następnym cyklu renderowania. możesz użyć zaczepu Effect, aby śledzić, czy jakikolwiek stan został zmieniony, czy nie.

useEffect(() => {
   console.log(testVariable);
}, [testVariable]);
2
Amit Chauhan 23 czerwiec 2021, 10:24

Zmień to na

const [testVariable, setTestVariable] = useState(false);

useEffect(()=> {
  testFunction();
}, [])

const testFunction = async () => {
  await timeout(1000);

  console.log("Setting test variable to: " + true);

  let newTestVariable = true;  
  setTestVariable(newTestVariable);

  await timeout(1000);
  
  console.log("Test variable is: " + newTestVariable);
}

Zmiana zmiennej stanu jest operacją asynchroniczną i działa z czymś, co nazywa się pętlą zdarzeń. Nie zostanie natychmiast zaktualizowany po ustawieniu setTestVariable(true).

0
Himanshu Kumar 23 czerwiec 2021, 10:49

async function zmienia stan, ale rejestrujesz testVariable w tym samym cyklu życia, dlatego wygląda na to, że stan się nie zmienił.

Jeśli zamiast tego zmienisz kod na

const [testVariable, setTestVariable] = React.useState(false)

console.log('testVariable', testVariable)
React.useEffect(() => {
  testFunction()
}, [])

const testFunction = async () => {
  await timeout(1000)
  setTestVariable(!testVariable)
}

return <h2>{testVariable}</h2>

Będzie rejestrować dane wyjściowe:

testVariable false
testVariable false
testVariable true
testVariable true

Powodem, dla którego pokazuje dwa logi dla obu false i true jest to, że console.log znajduje się poza React.useEffect(() => {}, []) (co jest równoważne componentDidMount dla stanowych komponentów React). React najpierw wykonuje console.log przed zamontowaniem komponentu, a następnie po zamontowaniu komponentu wykonuje kod wewnątrz React.useEffect i ponownie renderuje komponent, tym samym ponownie wykonując instrukcję console.log.

Aby zalogować się tylko raz, musisz zmienić React.useEffect na:

React.useEffect(() => {
  console.log('testVariable', testVariable)
  testFunction()
}, [testVariable])

Dodanie właściwości do argumentów tablicy [testVariable] zmienia React.useEffect z funkcji równoważnej componentDidMount na funkcję czatu wykonywaną w componentDidMount i dla każdego nowego stanu testVariable.

0
Kim Brun Jørgensen 23 czerwiec 2021, 11:38