Reputation: 397
Good day! I have a nested state with array children, and I would like to know the correct and best way to setState.
Here's a sample state object.
EDITED, Forgot to mention that lists
is an array of objects
.
this.state = {
lists:
[{
name: 'sampleList',
id: 15,
permission: {
canRead: true,
canWrite: false
}
}]
}
}
I use this to setState of the permission's properties but the state is not updated.
this.setState({
...this.state, lists: {
...this.state.lists, key: [
...this.state.lists.key, permission : {
...this.state.lists.key.permission,
canRead: !this.state.lists.key.permission.canRead
}
]
}
});
I hope you can help me. Thanks!
Upvotes: 2
Views: 69
Reputation: 179
The way to change a specific element of the array with setState
is to copy all items of array as they are without changing, except for the target item, this can be done with .map
and if
statement:
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
lists: [
{
name: 'sampleList',
id: 15,
permission: {
canRead: true,
canWrite: false
}
}
]
}
}
invertCanRead(targetId) {
this.setState({
...this.state,
lists: this.state.lists.map(list => {
if (list.id === targetId) {
// that is the one we want to modify, so let's return
// modified version:
return {
...list,
permission: {
...list.permission,
canRead: !list.permission.canRead
}
}
} else {
// else return list as is without changes because
// it's not the one we want to modify, so just copy it:
return list;
}
})
})
}
render() {
return <div>
{JSON.stringify(this.state)};
<button onClick={() => this.invertCanRead(15)}></button>
</div>
}
}
Upvotes: 1
Reputation: 112927
You can create a copy of the lists
array, and then replace the object of the index you want to change with a copy of that same object but where you change the permission
.
Example
class App extends React.Component {
state = {
lists: [
{
name: "sampleList",
id: 15,
permission: {
canRead: true,
canWrite: false
}
}
]
};
updateList = (index, canRead, canWrite) => {
this.setState(prevState => {
const lists = [...prevState.lists];
lists[index] = { ...lists[index], permission: { canRead, canWrite } };
return { lists };
});
};
render() {
return (
<div>
<button onClick={() => this.updateList(0, false, true)}>
Update state
</button>
<div>{JSON.stringify(this.state)}</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Upvotes: 2