简体   繁体   English

更新 state 两次时反应 useState,第一次更新被删除

[英]React useState when updating state twice, first update gets deleted

I noticed a behavior I cant understand how to solve, I never had it while I was writing react class based using this.setState but I get it while using useState hook.我注意到一个我无法理解如何解决的行为,我在编写基于 this.setState 的 react class 时从未遇到过,但我在使用 useState 钩子时得到了它。

for example:例如:

const Main = () => {
    const [values, setValues] = useState({val1: '', val2: '', val3: ''})
    const func1 = async () => {
        await setValues({
            ...values,
            val1: '111111111'
        });
        await func2();
     }
     const func2 = async () => {
          result = (fetch some data);
          await setValues({
              ...values,
              val2: result
           });
     }
 };

now if you run func1, val1 will be changed but as soon as func2 finishes and we setValues the second time val1 will get overwritten and val2 will contain value.现在,如果您运行 func1,val1 将被更改,但一旦 func2 完成并且我们第二次 setValues val1 将被覆盖并且 val2 将包含值。

what am I doing wrong and how can I fix this?我做错了什么,我该如何解决?

Thanks in Advance!提前致谢!

Edit:编辑:

在此处输入图像描述

when using Hooks I cant see what is the acctual anme of the value entered in the React Chrome Dev tool.使用 Hooks 时,我看不到在 React Chrome 开发工具中输入的值的实际名称是什么。 is there a way to fix this?有没有办法来解决这个问题? when I was having one useState containing an object I could see the titles of each object key... now its hidden -_-当我有一个包含 object 的 useState 时,我可以看到每个 object 键的标题......现在它隐藏了-_-

You're spreading the state before updating the correspondent property, try to chunk your state您在更新对应的属性之前传播 state,尝试分chunk您的 state

const Main = () => {
    const [value1, setValue1] = useState(null)
    const [value2, setValue2] = useState(null)
    const func1 = async () => {
        setValue1('foo')
        await func2();
     }
     const func2 = async () => {
          result = (fetch some data);
          await setValue2('foo')
     }
 };

Here is what is happening这是正在发生的事情

  • setValues is called changing val1 (state isn't updated yet) setValues称为更改val1 (状态尚未更新)

  • setValues is called again changing val2 and spreading the rest再次调用setValues更改val2spreading rest

By the time setValues spreads values val1 still holds it's initial value, overwriting the first setValues call.setValues传播valuesval1仍然保持它的初始值,覆盖第一个setValues调用。 Remember, changes in state are reflected asynchronously请记住,state 中的更改是异步反映的

React useState also takes a functional updater to update your component state similarly to how class-based component's setState works. React useState也需要一个函数更新器来更新你的组件 state 类似于基于类的组件的setState的工作方式。

Note笔记

Unlike the setState method found in class components, useState does not automatically merge update objects.与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。 You can replicate this behavior by combining the function updater form with object spread syntax:您可以通过将 function 更新程序表单与 object 扩展语法相结合来复制此行为:

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});

So in your code you could update as follows:因此,在您的代码中,您可以更新如下:

const Main = () => {
  const [values, setValues] = useState({val1: '', val2: '', val3: ''});

  const func1 = async () => {
    await setValues(prevState => ({
      ...prevState,
      val1: '111111111'
    }));
    await func2();
  }

  const func2 = async () => {
    result = (fetch some data);
    await setValues(prevState => ({
       ...prevState,
       val2: result
    }));
  }
};

I haven't tested it yet but maybe it could work as an alternative.我还没有测试过它,但也许它可以作为替代品。

Sometimes, when we need to get the value in the state, we usually do the spread operator within the state but it doesn't guarantees that the value is the correct one.有时,当我们需要获取 state 中的值时,我们通常会在 state 中进行扩展运算符,但这并不能保证该值是正确的。 For those cases, we better call setState with a callback which takes the previous value from state.对于这些情况,我们最好使用回调调用setState ,该回调从 state 获取先前的值。 So, you can use something like this:所以,你可以使用这样的东西:

setValues(prev => ({...prev, val1:'11111'}));

The behaviour of the code becomes clear once we note that values variable in func2 is clousre on values at outer scope, which is really a copy of state taken at the time useState was called.一旦我们注意到 func2 中的values变量与外部 scope 的values一致,代码的行为就会变得清晰,这实际上是在调用 useState 时获取的useState的副本。

So what your spreading in func2 is is stale copy of your state.因此,您在func2中的传播是 state 的陈旧副本。

One way of correcting this would be to use functional update纠正此问题的一种方法是使用功能更新

setValues((values) => ({...values, val2: result}));

This will make sure that you are using updated value of the state.这将确保您使用的是 state 的更新值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM