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.
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. If I click the second button, then only 2
will show and prop a
and c
are gone.
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()
.
Since you want to update a specific part of object: {}
, you can use the spread syntax or Object.assign()
as follows:
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
.
I can think of four ways to solve this, I'll show two of those.
onClick={this.setState({ object: { c: 3 }})}
to 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:
// 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()
:
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.
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>
);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.