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