J'essaie d'apprendre les crochets et la useState
méthode m'a rendu confus. J'attribue une valeur initiale à un état sous la forme d'un tableau. La méthode set dans useState
ne fonctionne pas pour moi même avec spread(...)
ou without spread operator
. J'ai créé une API sur un autre PC que j'appelle et récupère les données que je veux mettre dans l'état.
Voici mon 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);
Le setMovies(result)
ainsi que setMovies(...result)
ne fonctionne pas. Pourrait utiliser de l'aide ici.
Je m'attends à ce que la variable de résultat soit poussée dans le tableau des films.
la source
useEffect
Ce n'est peut-être pas la meilleure solution, car il ne prend pas en charge les appels asynchrones. Donc, si nous souhaitons effectuer une validation asynchrone sur lemovies
changement d'état, nous n'avons aucun contrôle dessus.the updater provided by useState hook
asynchrone ou non , contrairement à cethis.state
qui aurait pu être muté si ellethis.setState
était synchrone, la fermeture autourconst movies
resterait la même même siuseState
fourni une fonction synchrone - voir l'exemple dans ma réponsesetMovies(prevMovies => ([...prevMovies, ...result]));
travaillé pour moiDétails supplémentaires à la réponse précédente :
Bien que React
setState
soit asynchrone (à la fois les classes et les hooks), et qu'il soit tentant d'utiliser ce fait pour expliquer le comportement observé, ce n'est pas la raison pour laquelle cela se produit.TLDR: La raison est une portée de fermeture autour d'une
const
valeur immuable .Solutions:
lire la valeur dans la fonction de rendu (pas dans les fonctions imbriquées):
ajoutez la variable dans les dépendances (et utilisez la règle eslint react-hooks / exhaust-deps ):
utilisez une référence mutable (lorsque ce qui précède n'est pas possible):
Explication pourquoi cela se produit:
Si l'async était la seule raison, ce serait possible
await setState()
.Howerver, les deux
props
etstate
sont supposés être inchangés pendant 1 rendu .Avec les hooks, cette hypothèse est améliorée en utilisant des valeurs constantes avec le
const
mot - clé:La valeur peut être différente entre 2 rendus, mais reste une constante à l'intérieur du rendu lui-même et à l'intérieur des fermetures (les fonctions qui vivent plus longtemps même après la fin du rendu, par exemple
useEffect
, les gestionnaires d'événements, à l'intérieur de n'importe quelle Promise ou setTimeout).Pensez à suivre une implémentation fausse, mais synchrone , de type React:
la source
Je viens de terminer une réécriture avec useReducer, suite à l'article de @kentcdobs (réf ci-dessous) qui m'a vraiment donné un résultat solide qui ne souffre pas du tout de ces problèmes de fermeture.
voir: https://kentcdodds.com/blog/how-to-use-react-context-effectively
J'ai condensé son passe-partout lisible à mon niveau préféré de DRYness - la lecture de son implémentation sandbox vous montrera comment cela fonctionne réellement.
Profitez, je sais que je suis !!
avec un usage similaire à celui-ci:
Maintenant, tout persiste partout sur toutes mes pages
Agréable!
Merci Kent!
la source
Maintenant , vous devriez voir que votre code fait ne travail. Ce qui ne fonctionne pas, c'est le
console.log(movies)
. C'est parce quemovies
pointe vers l' ancien état . Si vous déplacez votreconsole.log(movies)
extérieur deuseEffect
, juste au-dessus du retour, vous verrez l'objet de films mis à jour.la source