Ich versuche Hooks zu lernen und die useState
Methode hat mich verwirrt. Ich weise einem Zustand in Form eines Arrays einen Anfangswert zu. Die eingestellte Methode in useState
funktioniert bei mir nicht einmal mit spread(...)
oder without spread operator
. Ich habe eine API auf einem anderen PC erstellt, den ich aufrufe, und die Daten abgerufen, die ich in den Status versetzen möchte.
Hier ist mein Code:
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);
Das funktioniert setMovies(result)
genauso gut wie setMovies(...result)
nicht. Könnte hier Hilfe gebrauchen.
Ich erwarte, dass die Ergebnisvariable in das Filmarray verschoben wird.
quelle
useEffect
Möglicherweise ist dies jedoch nicht die beste Lösung, da asynchrone Aufrufe nicht unterstützt werden. Wenn wir also eine asynchrone Validierung bei Statusänderungen durchführen möchtenmovies
, haben wir keine Kontrolle darüber.the updater provided by useState hook
asynchron ist oder nicht , im Gegensatz zu demthis.state
, der hätte mutiert werden können, wenn erthis.setState
synchron gewesen wäre, würde die Schließung auchconst movies
dann gleich bleiben, wennuseState
eine synchrone Funktion bereitgestellt - siehe das Beispiel in meiner AntwortsetMovies(prevMovies => ([...prevMovies, ...result]));
arbeitete für michZusätzliche Details zur vorherigen Antwort :
Während Reagieren der
setState
ist asynchron (beide Klassen und Haken), und es ist verlockend , diese Tatsache zu verwenden , um das beobachtete Verhalten zu erklären, ist es nicht der Grund , warum es passiert.TLDR: Der Grund ist ein Schließungsbereich um einen unveränderlichen
const
Wert.Lösungen:
Lesen Sie den Wert in der Renderfunktion (nicht in verschachtelten Funktionen):
Fügen Sie die Variable in Abhängigkeiten ein (und verwenden Sie die Eslint-Regel " react-hooks / erschöpfende-deps "):
Verwenden Sie eine veränderbare Referenz (wenn dies nicht möglich ist):
Erklärung, warum es passiert:
Wenn Async der einzige Grund wäre, wäre dies möglich
await setState()
.Es wird jedoch davon ausgegangen, dass beide
props
und während eines Renderns unverändert sind .state
Bei Hooks wird diese Annahme durch die Verwendung konstanter Werte mit dem
const
Schlüsselwort erweitert:Der Wert kann zwischen zwei Renderings unterschiedlich sein, bleibt jedoch innerhalb des Renderings selbst und innerhalb aller Schließungen konstant (Funktionen, die auch nach Abschluss des
useEffect
Renderns länger gültig sind , z. B. Ereignishandler, innerhalb eines Promise oder setTimeout).Betrachten Sie die folgende gefälschte, aber synchrone , reaktionsähnliche Implementierung:
quelle
Ich habe gerade eine Umschreibung mit useReducer abgeschlossen, die dem Artikel @kentcdobs (siehe unten) folgt und mir wirklich ein solides Ergebnis liefert, das nicht ein bisschen unter diesen Schließungsproblemen leidet.
Siehe: https://kentcdodds.com/blog/how-to-use-react-context-effectively
Ich habe seine lesbare Boilerplate auf mein bevorzugtes Maß an Trockenheit verdichtet - das Lesen seiner Sandbox-Implementierung zeigt Ihnen, wie es tatsächlich funktioniert.
Viel Spaß, ich weiß ich bin !!
mit einer ähnlichen Verwendung:
Jetzt bleibt alles auf allen meinen Seiten reibungslos
Nett!
Danke Kent!
quelle
Jetzt sollten Sie sehen, dass Ihr Code tatsächlich funktioniert . Was nicht funktioniert ist das
console.log(movies)
. Dies liegt daran, dassmovies
auf den alten Zustand hingewiesen wird . Wenn Sie Ihreconsole.log(movies)
AußenseiteuseEffect
direkt über der Rückgabe verschieben, wird das aktualisierte Filmobjekt angezeigt.quelle