当前位置: 首页 > 知识库问答 >
问题:

useState set方法不会立即反映更改

司空和悌
2023-03-14

我正在尝试学习挂钩,useState方法让我感到困惑。我正在以数组的形式为状态分配初始值。useState中的set方法不适合我,无论是否使用扩展语法。

我在另一台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>

无论是设置电影(结果)还是设置电影(结果)都不起作用。

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


共有3个答案

戚良弼
2023-03-14

我知道已经有很好的答案了。但我想给出另一个解决相同问题的方法,并使用我的模块react useStateRef访问最新的“电影”状态。

正如您所理解的,通过使用React state,您可以在每次状态更改时呈现页面。但通过使用React ref,您始终可以获得最新的值。

因此,模块react-useStateRef允许您同时使用state和ref。它向下兼容React.useState,因此您可以替换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);
      }
    })();
  }, []);
  • react usestsateref
云凌
2023-03-14
匿名用户

上一个答案的其他详细信息:

虽然React的setState是异步的(类和挂钩),并且很容易使用这个事实来解释观察到的行为,但这并不是它发生的原因。

TLDR:原因是围绕不可变的常量值的闭包范围。

>

  • 读取渲染函数中的值(不在嵌套函数中):

      useEffect(() => { setMovies(result) }, [])
      console.log(movies)
    

    将变量添加到依赖项中(并使用react hooks/deps-eslint规则):

      useEffect(() => { setMovies(result) }, [])
      useEffect(() => { console.log(movies) }, [movies])
    

    使用临时变量

      useEffect(() => {
        const newMovies = result
        console.log(newMovies)
        setMovies(newMovies)
      }, [])
    

    使用可变引用(如果我们不需要状态并且只想记住值-更新ref不会触发重新渲染):

      const moviesRef = useRef(initialValue)
      useEffect(() => {
        moviesRef.current = result
        console.log(moviesRef.current)
      }, [])
    

    如果异步是唯一的原因,则可以等待setState()。

    但是,假定在1次渲染期间,道具和状态都不变。

    处理此问题。将其设置为不可变状态。

    使用挂钩,通过使用带有const关键字的常量值来增强此假设:

    const [state, setState] = useState('initial')
    

    该值在两个渲染之间可能不同,但在渲染本身和任何闭包内保持不变(即使在渲染完成后仍然有效的函数,例如,useffect、事件处理程序、任何Promise或setTimeout内)。

    考虑以下虚假但同步的类反应实现:

    // sync implementation:
    
    let internalState
    let renderAgain
    
    const setState = (updateFn) => {
      internalState = updateFn(internalState)
      renderAgain()
    }
    
    const useState = (defaultState) => {
      if (!internalState) {
        internalState = defaultState
      }
      return [internalState, setState]
    }
    
    const render = (component, node) => {
      const {html, handleClick} = component()
      node.innerHTML = html
      renderAgain = () => render(component, node)
      return handleClick
    }
    
    // test:
    
    const MyComponent = () => {
      const [x, setX] = useState(1)
      console.log('in render:', x) // ✅
      
      const handleClick = () => {
        setX(current => current + 1)
        console.log('in handler/effect/Promise/setTimeout:', x) // ❌ NOT updated
      }
      
      return {
        html: `<button>${x}</button>`,
        handleClick
      }
    }
    
    const triggerClick = render(MyComponent, document.getElementById('root'))
    triggerClick()
    triggerClick()
    triggerClick()
    <div id="root"></div>

  • 李开宇
    2023-03-14

    很像扩展React创建的类组件中的. setState()。ComponentReact。PureComponent,使用useState挂钩提供的更新程序进行状态更新也是异步的,不会立即反映。

    此外,这里的主要问题不仅仅是异步性质,还有一个事实,即状态值是由函数根据其当前闭包使用的,状态更新将反映在下一次重新呈现中,现有闭包不会受到影响,而是会创建新的闭包。现在,在当前状态下,钩子中的值由现有闭包获得,当重新呈现时,闭包将根据是否重新创建函数进行更新。

    即使您添加了setTimeout函数,尽管超时将在重新渲染发生的一段时间后运行,但setTimeout仍将使用其先前闭包中的值而不是更新的闭包。

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

    如果要对状态更新执行操作,需要使用useffect挂钩,就像在类组件中使用componentdiddupdate一样,因为useState返回的setter没有回调模式

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

    就更新状态的语法而言,setMovies(result)将用异步请求中可用的值替换状态中以前的值。

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

    setMovies(prevMovies => ([...prevMovies, ...result]));
    
     类似资料:
    • 我试图学习钩子,而方法让我感到困惑。我以数组的形式给一个状态赋值初始值。中的set方法不适用于我,无论是否使用扩频运算符。 我在另一台PC上制作了一个API,我正在调用它并获取我想要设置为状态的数据。 这是我的代码: 和都不起作用。 我希望结果变量被推送到movies数组中。

    • 问题内容: 我正在尝试学习钩子,该方法使我感到困惑。我正在将初始值分配给数组形式的状态。即使使用或,in中的set方法对我也不起作用。我已经在另一台PC上创建了一个API,该API正在调用并获取要设置为状态的数据。 这是我的代码: 的以及不工作。可以在这里使用一些帮助。 我希望将结果变量推入movies数组中。 问题答案: 类似于通过扩展或创建的Class组件中的setState,使用钩子提供的更

    • 问题内容: 我正在做一个待办事项应用程序。这是违规代码的非常简化的版本。我有一个复选框: 这是调用复选框的函数: updateItem是映射为分派到redux的函数 我的问题是,当我调用updateItem操作并在console.log状态时,它总是落后1步。如果未选中该复选框且该复选框不为true,则仍将状态为true传递给updateItem函数。我是否需要调用另一个函数来强制状态更新? 问题

    • 每当我使用useState设置变量时,该值不会立即反映出来。这里我有一个useEffect调用computePriceSummary(); computePriceSummary调用三个函数,如图所示: 这些函数使用useState设置变量: 浏览器中显示的值包括: Stackoverflow中的解决方案建议使用useEffect跟踪变量,因此我做了: 结果还是一样。

    • 我想问一下,为什么在执行事件时,我的状态没有改变。我已经搜索到需要在构造函数中绑定函数,但是状态仍然没有更新。 下面是我的代码:

    • 问题内容: 我想问为什么在执行onclick事件时状态没有变化。我已经搜索了一段时间,我需要在构造函数中绑定onclick函数,但状态仍未更新。这是我的代码: 问题答案: 这个回调真的很混乱。只需使用async await代替: