【问题标题】:Correct way to update an objects state in react (Merged state? Spread operators?)在反应中更新对象状态的正确方法(合并状态?传播运算符?)
【发布时间】:2021-09-15 07:14:34
【问题描述】:

我使用 React 已经有一段时间了,我总是使用扩展运算符更新对象的状态,因为我记得读过你应该直接更改当前状态。

例如,现在我写这样的东西:

const changeState = () => {
  setState(prevState => {...prevState, existingKey: 'new value'})
} 

但我刚刚在 React 文档 (https://reactjs.org/docs/state-and-lifecycle.html#state-updates-are-merged) 中遇到了“合并状态更新”部分。如果我理解正确的话,本质上是说我可以改写这个:

const changeState = () => {
  setState({existingKey: 'new value'})
} 

并且对象中的所有其他键将保持原样,只有我指定的键将在状态中更新。我读对了吗?我从来没有在stackoverflow上看到过这个,我总是看到有人说要使用扩展运算符,有什么原因吗?

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    推荐功能状态更新和浅拷贝的原因是它适用于所有用例。您引用的state-updates-are-merged 链接实际上适用于基于类的组件的this.setState 方法。

    • 在单个渲染周期、循环等中将多个更新排入队列...

      this.setState({ count: this.state.count + 1 });
      this.setState({ count: this.state.count + 1 });
      this.setState({ count: this.state.count + 1 });
      

      这里的最终结果只是一个 count + 1 更新,因为每次更新都会覆盖前一次。

      this.setState(prevState => ({ count: prevState.count + 1 }));
      this.setState(prevState => ({ count: prevState.count + 1 }));
      this.setState(prevState => ({ count: prevState.count + 1 }));
      

      这里的最终结果现在是count + 3

    • 在回调中引用以前的状态以避免陈旧的外壳。

       componentDidMount() {
         setInterval(() => this.setState({ count:  this.state.count + 1 }), 1000);
       }
      

      这里初始的count 状态在回调范围内被关闭并且永远不会更新。

       componentDidMount() {
         setInterval(() => this.setState(prevState => { count:  prevState.count + 1 }), 1000);
       }
      
    • 只有根属性被合并,更深的嵌套状态被更新也需要浅拷贝。

       this.setState(prevState => ({
         ...prevState,
         property: {
           ...prevState.property,
           nestedProperty: 'new value',
         },
       }));
      
    • 如果您正在使用 useState 挂钩,则状态更新不会浅合并。

      useState

      与类组件中的 setState 方法不同,useState 可以 不会自动合并更新对象。你可以复制这个 通过将函数更新器形式与对象传播相结合的行为 语法:

      const [state, setState] = useState({});
      setState(prevState => {
        // Object.assign would also work
        return {...prevState, ...updatedValues};
      });
      

    一个好的经验法则

    如果下一个状态依赖任何方式之前的状态,则使用功能状态更新。否则,定期更新就足够了。

    【讨论】:

      【解决方案2】:

      对于函数式组件,语法为:

      const changeState = () => {
        setState(prevState => {...prevState, existingKey: 'new value'})
      } 
      

      对于类组件,语法为:

      const changeState = () => {
        // Notice the use of this
        this.setState({existingKey: 'new value'})
      } 
      

      【讨论】:

        【解决方案3】:
        //Use react hooks for the functional component
        
        import React, { useState, useEffect } from 'react';
        
        //Suppose a user object with name, age, gender properties.
        
        let [userData, setUserData] = useState({
            name: "Somnath Jana",
            age:27
            gender: "Male"
        })
        
        useEffect(()=>{
           userData.age = 28
           setUserData({...userData})
        },[])
        

        【讨论】:

        • 仅供参考 userData.age = 28 改变状态对象。
        • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
        • 是的,我以为您不应该这样做,并且您应该在更改年龄属性之前创建 userData 的副本。
        猜你喜欢
        • 2018-06-06
        • 1970-01-01
        • 2021-04-29
        • 2020-02-27
        • 1970-01-01
        • 2020-12-07
        • 2021-09-14
        • 2020-11-11
        • 1970-01-01
        相关资源
        最近更新 更多