Estoy tratando de aprender ganchos y el useState
método me ha confundido. Estoy asignando un valor inicial a un estado en forma de matriz. El método set en useState
no me funciona incluso con spread(...)
o without spread operator
. He hecho una API en otra PC a la que estoy llamando y obteniendo los datos que quiero establecer en el estado.
Aquí está mi código:
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);
El setMovies(result)
bien como setMovies(...result)
no funciona. Podría usar algo de ayuda aquí.
Espero que la variable de resultado se inserte en la matriz de películas.
fuente
useEffect
Sin embargo, podría no ser la mejor solución, ya que no admite llamadas asincrónicas. Entonces, si quisiéramos hacer una validación asíncrona en elmovies
cambio de estado, no tenemos control sobre eso.the updater provided by useState hook
es asíncrono o no , a diferencia de lothis.state
que podría haber sido mutado sithis.setState
fuera sincrónico, el cierreconst movies
seguiría siendo el mismo incluso siuseState
proporcionó una función sincrónica - vea el ejemplo en mi respuestasetMovies(prevMovies => ([...prevMovies, ...result]));
trabajó para míDetalles adicionales a la respuesta anterior :
Si bien React's
setState
es asíncrono (tanto clases como ganchos), y es tentador usar ese hecho para explicar el comportamiento observado, no es la razón por la que sucede.TLDR: La razón es un alcance de cierre alrededor de un
const
valor inmutable .Soluciones:
lea el valor en la función de representación (no dentro de las funciones anidadas):
agregue la variable en dependencias (y use la regla react-hooks / exhaustive-deps eslint):
use una referencia mutable (cuando lo anterior no es posible):
Explicación por qué sucede:
Si async fuera la única razón, sería posible
await setState()
.Howerver, ambos
props
ystate
se supone que no cambian durante 1 render .Con ganchos, esta suposición se mejora mediante el uso de valores constantes con la
const
palabra clave:El valor puede ser diferente entre 2 renders, pero permanece constante dentro del render en sí y dentro de cualquier cierre (funciones que duran más, incluso después de que finaliza el render, por ejemplo
useEffect
, controladores de eventos, dentro de cualquier Promise o setTimeout).Considere seguir una implementación falsa, pero sincrónica , similar a React:
fuente
Acabo de terminar una reescritura con useReducer, siguiendo el artículo de @kentcdobs (referencia a continuación) que realmente me dio un resultado sólido que no sufre ni un poco de estos problemas de cierre.
ver: https://kentcdodds.com/blog/how-to-use-react-context-effectively
Condensé su repetitivo legible a mi nivel preferido de SECADO: leer su implementación de sandbox le mostrará cómo funciona realmente.
Disfruta, sé que lo estoy !!
con un uso similar a este:
Ahora todo persiste sin problemas en todas partes en todas mis páginas
¡Agradable!
Gracias Kent!
fuente
Ahora debería ver, que su código en realidad hace el trabajo. Lo que no funciona es el
console.log(movies)
. Esto se debe a quemovies
apunta al estado anterior . Si mueve suconsole.log(movies)
exterioruseEffect
, justo encima del retorno, verá el objeto de películas actualizado.fuente