useState set 方法不会立即反映更改 [英] useState set method not reflecting change immediately

查看:19
本文介绍了useState set 方法不会立即反映更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试学习钩子,而 useState 方法让我感到困惑.我正在为数组形式的状态分配一个初始值.useState 中的 set 方法对我不起作用,无论有没有扩展运算符.

I am trying to learn hooks and the useState method has made me confused. I am assigning an initial value to a state in the form of an array. The set method in useState is not working for me, both with and without the spread operator.

我在另一台 PC 上创建了一个 API,我正在调用它并获取我想要设置到状态中的数据.

I have made an API on another PC that I am calling and fetching the data which I want to set into the state.

这是我的代码:

<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) 都不起作用.

我希望将结果变量推送到电影数组中.

I expect the result variable to be pushed into the movies array.

推荐答案

很像 Class 组件中的 setState 通过扩展 React.ComponentReact.PureComponent 创建的状态,状态使用 useState 钩子提供的更新器更新也是异步的,不会立即反映.

Much like setState in Class components created by extending React.Component or React.PureComponent, the state update using the updater provided by useState hook is also asynchronous, and will not be reflected immediately.

此外,这里的主要问题不仅是异步性质,还在于函数根据当前闭包使用状态值,状态更新将反映在下一次重新渲染中,现有闭包通过不受影响,但会创建新的.现在在当前状态下,钩子中的值是由现有的闭包获取的,当重新渲染发生时,闭包会根据函数是否再次重新创建而更新.

Also, the main issue here is not just the asynchronous nature but the fact that state values are used by functions based on their current closures, and state updates will reflect in the next re-render by which the existing closures are not affected, but new ones are created. Now in the current state, the values within hooks are obtained by existing closures, and when a re-render happens, the closures are updated based on whether the function is recreated again or not.

即使您添加了 setTimeout 函数,虽然超时会在重新渲染发生的一段时间后运行,setTimeout 仍将使用值来自其前一个闭包而不是更新的闭包.

Even if you add a setTimeout the function, though the timeout will run after some time by which the re-render would have happened, the setTimeout will still use the value from its previous closure and not the updated one.

setMovies(result);
console.log(movies) // movies here will not be updated

如果你想对状态更新执行一个动作,你需要使用useEffect钩子,就像在类组件中使用componentDidUpdate一样,因为useState返回的setter没有回调模式

If you want to perform an action on state update, you need to use the useEffect hook, much like using componentDidUpdate in class components since the setter returned by useState doesn't have a callback pattern

useEffect(() => {
    // action on update of movies
}, [movies]);

就更新状态的语法而言,setMovies(result) 会将状态中先前的 movies 值替换为异步请求中可用的值.

As far as the syntax to update state is concerned, setMovies(result) will replace the previous movies value in the state with those available from the async request.

但是,如果要将响应与先前存在的值合并,则必须使用状态更新的回调语法以及正确使用传播语法,例如

However, if you want to merge the response with the previously existing values, you must use the callback syntax of state updation along with the correct use of spread syntax like

setMovies(prevMovies => ([...prevMovies, ...result]));

这篇关于useState set 方法不会立即反映更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆