Estoy tratando de aprender ganchos y el método useState
me ha confundido. Estoy asignando un valor inicial a un estado en forma de matriz. El método set en useState
no funciona para mí, tanto con como sin la sintaxis de propagación.
Creé una API en otra PC a la que llamo y obtengo los datos que quiero configurar en el estado.
Aquí está mi código:
<div id="root"></div> <script type="text/babel" defer> // import React, { useState, useEffect } from "react"; // import ReactDOM from "react-dom"; const { useState, useEffect } = React; // web-browser variant 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 =", result); setMovies(result); console.log("movies =", movies); } catch (e) { console.error(e); } })(); }, []); return <p>hello</p>; }; const rootElement = document.getElementById("root"); ReactDOM.render(<StateSelector />, rootElement); </script> <script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script> <script src="https://unpkg.com/react@17/umd/react.production.min.js"></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
Ni setMovies(result)
ni setMovies(...result)
funcionan.
Espero que la variable de result
se inserte en la matriz de movies
.
Al igual que los componentes setState in Class creados mediante la extensión de React.Component
o React.PureComponent
, la actualización de estado mediante el actualizador proporcionado por useState
hook también es asíncrona y no se reflejará de inmediato.
Además, el problema principal aquí no es solo la naturaleza asíncrona, sino el hecho de que las funciones utilizan los valores de estado en función de sus cierres actuales, y las actualizaciones de estado se reflejarán en la próxima representación por la cual los cierres existentes no se ven afectados, sino nuevos. se crean unos . Ahora, en el estado actual, los valores dentro de los ganchos se obtienen de los cierres existentes, y cuando ocurre una nueva representación, los cierres se actualizan en función de si la función se vuelve a crear o no.
Incluso si agrega un setTimeout
a la función, aunque el tiempo de espera se ejecutará después de un tiempo en el que se habría producido la nueva representación, setTimeout
seguirá utilizando el valor de su cierre anterior y no el actualizado.
setMovies(result); console.log(movies) // movies here will not be updated
Si desea realizar una acción en la actualización del estado, debe usar el useEffect
, de forma similar al uso de componentDidUpdate
en los componentes de la clase, ya que el setter devuelto por useState
no tiene un patrón de devolución de llamada.
useEffect(() => { // action on update of movies }, [movies]);
En lo que respecta a la sintaxis para actualizar el estado, setMovies(result)
reemplazará el valor de las movies
anteriores en el estado con los disponibles de la solicitud asíncrona.
Sin embargo, si desea fusionar la respuesta con los valores existentes anteriormente, debe usar la sintaxis de devolución de llamada de la actualización de estado junto con el uso correcto de la sintaxis extendida como
setMovies(prevMovies => ([...prevMovies, ...result]));
Sé que ya hay muy buenas respuestas. Pero quiero dar otra idea de cómo resolver el mismo problema y acceder al último estado de 'película', usando mi módulo react-useStateRef .
Como comprenderá, al usar el estado React puede representar la página cada vez que cambia el estado. Pero al usar React ref, siempre puede obtener los valores más recientes.
Entonces, el módulo react-useStateRef
le permite usar estados y referencias juntos. Es compatible con versiones anteriores de React.useState
, por lo que puede reemplazar la declaración de import
const { useEffect } = React import { useState } from 'react-usestateref' const [movies, setMovies] = useState(initialValue); useEffect(() => { (async function() { try { const result = [ { id: "1546514491119", }, ]; console.log("result =", result); setMovies(result); console.log("movies =", movies.current); // will give you the latest results } catch (e) { console.error(e); } })(); }, []);