Próbuję się nauczyć haczyków, a useState
metoda wprawiła mnie w zakłopotanie. Przypisuję wartość początkową do stanu w postaci tablicy. Metoda set w useState
nie działa nawet z spread(...)
lub without spread operator
. Zrobiłem API na innym komputerze, który wywołuję i pobieram dane, które chcę ustawić w stanie.
Oto mój kod:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const StateSelector = () => {
const initialValue = [
{
category: "",
photo: "",
description: "",
id: 0,
name: "",
rating: 0
}
];
const [movies, setMovies] = useState(initialValue);
useEffect(() => {
(async function() {
try {
//const response = await fetch(
//`http://192.168.1.164:5000/movies/display`
//);
//const json = await response.json();
//const result = json.data.result;
const result = [
{
category: "cat1",
description: "desc1",
id: "1546514491119",
name: "randomname2",
photo: null,
rating: "3"
},
{
category: "cat2",
description: "desc1",
id: "1546837819818",
name: "randomname1",
rating: "5"
}
];
console.log(result);
setMovies(result);
console.log(movies);
} catch (e) {
console.error(e);
}
})();
}, []);
return <p>hello</p>;
};
const rootElement = document.getElementById("root");
ReactDOM.render(<StateSelector />, rootElement);
Tak setMovies(result)
dobrze, jak setMovies(...result)
nie działa. Przydałaby się tutaj pomoc.
Oczekuję, że zmienna wynikowa zostanie umieszczona w tablicy filmów.
źródło
useEffect
może jednak nie być najlepszym rozwiązaniem, ponieważ nie obsługuje wywołań asynchronicznych. Tak więc, jeśli chcielibyśmy dokonać asynchronicznej weryfikacjimovies
zmiany stanu, nie mamy nad tym żadnej kontroli.the updater provided by useState hook
jest asynchroniczne, w przeciwieństwie dothis.state
tego , które mogłoby zostać zmutowane, gdybythis.setState
było synchroniczne, Zamknięcie wokółconst movies
pozostanie takie samo, nawet jeśliuseState
setMovies(prevMovies => ([...prevMovies, ...result]));
pracował dla mnieDodatkowe szczegóły do poprzedniej odpowiedzi :
Chociaż React
setState
jest asynchroniczny (zarówno klasy, jak i hooki) i kuszące jest wykorzystanie tego faktu do wyjaśnienia obserwowanego zachowania, nie jest to powód, dla którego tak się dzieje.TLDR: Przyczyną jest zamknięcie zakresu wokół niezmiennej
const
wartości.Rozwiązania:
odczytaj wartość w funkcji renderowania (nie wewnątrz funkcji zagnieżdżonych):
dodaj zmienną do zależności (i użyj reguły React -hooks / wyczerpująco-deps eslint):
użyj zmiennego odniesienia (gdy powyższe nie jest możliwe):
Wyjaśnienie, dlaczego tak się dzieje:
Gdyby async był jedynym powodem, byłoby to możliwe
await setState()
.Jednak oba
props
istate
są niezmienne podczas 1 renderowania .W przypadku haków to założenie jest wzmocnione przez użycie stałych wartości ze
const
słowem kluczowym:Wartość może być różna w 2 renderach, ale pozostaje stała wewnątrz samego renderowania i wewnątrz wszelkich zamknięć (funkcji, które działają dłużej nawet po zakończeniu renderowania, np.
useEffect
Programy obsługi zdarzeń, wewnątrz dowolnego Promise lub setTimeout).Rozważ następującą fałszywą, ale synchroniczną implementację podobną do React:
źródło
Właśnie skończyłem przepisywanie z useReducer, po artykule @kentcdobs (ref poniżej), który naprawdę dał mi solidny wynik, który ani trochę nie cierpi z powodu tych problemów z zamykaniem.
widzieć: https://kentcdodds.com/blog/how-to-use-react-context-effectively
Skondensowałem jego czytelny szablon do mojego preferowanego poziomu SUCHOŚCI - przeczytanie jego implementacji w piaskownicy pokaże ci, jak to naprawdę działa.
Ciesz się, wiem, że jestem !!
o zastosowaniu podobnym do tego:
Teraz wszystko działa płynnie na wszystkich moich stronach
Miły!
Dzięki, Kent!
źródło
Teraz powinieneś zobaczyć, że Twój kod faktycznie wykonuje pracę. To, co nie działa, to
console.log(movies)
. To dlatego, żemovies
wskazuje na stary stan . Jeśli przesuniesz swojąconsole.log(movies)
zewnętrzną stronęuseEffect
, tuż nad zwrotem, zobaczysz zaktualizowany obiekt filmów.źródło