我正在尝试学习钩子,但这种useState方法让我感到困惑。我正在以数组的形式为状态分配初始值。无论有没有传播语法, set 方法useState都对我不起作用。
useState
我在另一台 PC 上创建了一个 API,我正在调用它并获取我想要设置为状态的数据。
这是我的代码:
<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>
既不setMovies(result)也不setMovies(...result)工作。
setMovies(result)
setMovies(...result)
我希望将result变量推入movies数组。
result
movies
React.Component与扩展or创建的 Class 组件中的 setState 一样React.PureComponent,使用 hook 提供的 updater 进行状态更新useState也是异步的,不会立即反映。
React.Component
React.PureComponent
此外,这里的主要问题不仅仅是异步性质,而是函数基于当前闭包使用状态值这一事实,并且状态更新将反映在下一次重新渲染中,现有闭包不受影响,而是新的那些被创建 。现在在当前状态下,钩子中的值是由现有的闭包获得的,当重新渲染发生时,闭包会根据函数是否再次重新创建而更新。
即使您添加了一个setTimeout函数,尽管超时将在重新渲染发生的一段时间后运行,但setTimeout仍将使用其先前关闭的值而不是更新的值。
setTimeout
setMovies(result); console.log(movies) // movies here will not be updated
如果要对状态更新执行操作,则需要使用 useEffect 挂钩,就像componentDidUpdate在类组件中使用一样,因为 useState 返回的 setter 没有回调模式
componentDidUpdate
useEffect(() => { // action on update of movies }, [movies]);
就更新状态的语法而言,setMovies(result)将用异步请求中可用的值替换状态中的先前movies值。
但是,如果要将响应与先前存在的值合并,则必须使用状态更新的回调语法以及正确使用传播语法,例如
setMovies(prevMovies => ([...prevMovies, ...result]));