React中复杂状态的深度合并

7
当我声明以下初始状态时:
  getInitialState: function() {
    return {
      isValid: false,
      metaData: {
        age: 12,
        content_type: 'short_url'
      }
    };
  },

我使用 setState 来更新状态,代码如下:

...
let newMetaData = {  age: 20 };
...
this.setState({
        isValid: true,
        metaData: newMetaData
      });
...

最终的this.state.metadata对象只定义了年龄属性。但据我所知,this.setState()会将其参数合并到现有状态中。那为什么这里不起作用,难道这不应该是递归合并吗?

在React/ES6中有一种方法可以将新对象属性合并到状态对象属性中吗?


1
ES6 展开运算符 - KOTIOS
4个回答

8

setState 执行浅合并。如果 metaData 是平面的:

this.setState({
  metaData: Object.assign({}, this.state.metaData, newMetaData),
});

或者,如果使用 spread:
this.setState({
  metaData: { ...this.state.metaData, ...newMetaData },
});

10
展开运算符合并不是“深度”合并,这意味着合并是递归的。此外,嵌套对象属性不会被合并。 - dodortus

1

setState还可以接受一个函数作为参数,该函数接收一个状态参数,您可以使用lodash merge来进行深度合并。

  setState(state => merge(state, yourPartialObjectToBeDeepMerged));

1

如果你只需要更新一个属性,另一种方法是这样的:

this.setState({
  metaData: {
    ...this.state.metaData,
    age: 20
  }
})

0

一个棘手的解决方案在这里

const [complexObject, setComplexObject] = useState({a:{b:{c:1}}})
setComplexObject((s)=>{
  s.a.b.c = 2
  return {...s}
})

它是如何工作的?

对象是一个引用。如果你 s.a.b.c = 2,这将更新状态,但组件不会重新渲染,因此dom不会改变。

然后我们需要一种方法来重新渲染组件。如果你 setComplexObject(s=>s),它不会触发重新渲染,因为尽管 ComplexObject 的内部发生了变化,但引用仍然指向同一个对象。

因此,我们需要使用 ES6 扩展运算符通过执行 {...s} 来重构一个对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接