简体   繁体   English

ReactJS:使用 setState() 更新嵌套状态对象属性而不替换整个对象

[英]ReactJS: Update nested state object properties without replacing whole object using setState()

I am trying to apply best practices when changing multiple property values of a nested object in my component's state.我正在尝试在组件状态下更改嵌套对象的多个属性值时应用最佳实践。

My component code currently looks like this:我的组件代码目前如下所示:

class App extends Component {
  state = {
    object: {
      a: 10,
      b: 7,
      c: 12,
    }
  }
  render() {
    return (
      <div>
        <button onClick={this.setState({ object: { a: 5 }})}>change value a </button>
        <button onClick={this.setState({ object: { b: 2 }})}>change value b </button>
        <button onClick={this.setState({ object: { c: 3 }})}>change value c </button>
      </div>
      <p>{this.state.object.a}</p>
      <p>{this.state.object.b}</p>
      <p>{this.state.object.c}</p>
    );
  }
}

Before any button is clicked, you see three buttons followed by paragraphs reading 10 , 7 and 12 on the page.在单击任何按钮之前,您会在页面上看到三个按钮,然后是阅读10712的段落。

Once I click the first button labeled "change value a", value b and c are destroyed in my components state object which causes only the value of 5 to show.单击标记为“更改值 a”的第一个按钮后,我的组件状态对象中的值bc被销毁,这会导致仅显示值5 If I click the second button, then only 2 will show and prop a and c are gone.如果我单击第二个按钮,则只有2将显示并且 prop ac消失了。

I understand the behaviour, however I would like to know the best way to solve it.我理解这种行为,但是我想知道解决它的最佳方法。 I want to keep it so all the values showing, and be able to update them in any order while the other values remain.我想保留它以便显示所有值,并且能够在保留其他值的同时以任何顺序更新它们。

I am also pretty sure I am mutating the state directly and I know this is bad practice.我也很确定我是直接改变状态,我知道这是不好的做法。 I just don't know the right practice in this situation.在这种情况下,我只是不知道正确的做法。

First to address what you said, "I am mutating the state directly" .首先解决你所说的, “我正在直接改变状态”

You are are not mutating state directly since you are calling this.setState() .您没有直接改变状态,因为您正在调用this.setState()

Since you want to update a specific part of object: {} , you can use the spread syntax or Object.assign() as follows:由于您要更新object: {}的特定部分object: {} ,您可以使用传播语法或Object.assign()如下:

this.setState({ object: { ...this.state.object, a: 5 } })

or或者

this.setState({ object: Object.assign({}, this.state.object, { a: 5 }) })

Because you called this.setState() in render , you will get the Maximum call stack exceeded error .因为你在render调用了this.setState() ,你会得到Maximum call stack exceeded error

I can think of four ways to solve this, I'll show two of those.我可以想到四种方法来解决这个问题,我将展示其中的两种。

  1. Extract your call into a class method, then pass the reference to the click event handler.将您的调用提取到类方法中,然后将引用传递给单击事件处理程序。
  2. Change this onClick={this.setState({ object: { c: 3 }})} to onClick={() => this.setState({ object: { c: 3 }})}将此onClick={this.setState({ object: { c: 3 }})}更改为onClick={() => this.setState({ object: { c: 3 }})}

One way to do this would be by using the spread ... operator on the nested object to merge the update of say { a: 5 } , with the prior state of the object field:一种方法是在嵌套object上使用 spread ...运算符将 say { a: 5 }的更新与object字段的先前状态合并:

// Create a new state object, with updated value of "5" for nested field "object.a"
{ object: { ...state.object, a: 5 }}

There are a few ways to incorporate this with setState() - one simple way is via a callback passed to setState() :有几种方法可以将其与setState()合并 - 一种简单的方法是通过传递给setState()的回调:

this.setState(state => { object: { ...state.object, a: 5 }})

This allow you to merge the nested object s prior state, with the state changes such as { a : 5 } on object , without completely replacing all the nested object value in your state.这使您可以合并嵌套object事先状态,随着国家的变化,如{ a : 5 }object ,而没有完全更换所有的嵌套的object在你的状态值。

In the case of your render function, you could update the rendered result like so:对于渲染函数,您可以像这样更新渲染结果:

 render() {
  return (
  <div>
    <button onClick={ () => this.setState(state => { object: { ...state.object, a: 5 }})}>change value a </button>
    <button onClick={ () => this.setState(state => { object: { ...state.object, b: 2 }})}>change value b </button>
    <button onClick={ () => this.setState(state => { object: { ...state.object, c: 5 }})}>change value c </button>
  </div>
  <p>{this.state.object.a}</p>
  <p>{this.state.object.b}</p>
  <p>{this.state.object.c}</p>
  );
  }

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

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