I have a state object that contains an array of objects:
this.state = {
feeling: [
{ name: 'alert', status: false },
{ name: 'calm', status: false },
{ name: 'creative', status: false },
{ name: 'productive', status: false },
{ name: 'relaxed', status: false },
{ name: 'sleepy', status: false },
{ name: 'uplifted', status: false }
]
}
I want to toggle the boolean status
from true to false on click event. I built this function as a click handler but it doesn't connect the event into the state change:
buttonToggle = (event) => {
event.persist();
const value = !event.target.value
this.setState( prevState => ({
status: !prevState.status
}))
}
I'm having a hard time following the control flow of the nested React state change, and how the active event makes the jump from the handler to the state object and vice versa.
The whole component:
export default class StatePractice extends React.Component {
constructor() {
super();
this.state = {
feeling: [
{ name: 'alert', status: false },
{ name: 'calm', status: false },
{ name: 'creative', status: false },
{ name: 'productive', status: false },
{ name: 'relaxed', status: false },
{ name: 'sleepy', status: false },
{ name: 'uplifted', status: false }
]
}
}
buttonToggle = (event) => {
event.persist();
const value = !event.target.value
this.setState( prevState => ({
status: !prevState.status
}))
}
render() {
return (
<div>
{ this.state.feeling.map(
(stateObj, index) => {
return <button
key={ index }
onClick={ this.buttonToggle }
value={ stateObj.status } >
{ stateObj.status.toString() }
</button>
}
)
}
</div>
)
}
}
Updating a nested object in a react state object is tricky. You have to get the entire object from the state in a temporary variable, update the value within that variable and then replace the state with the updated variable. To do that, your buttonToggle function needs to know which button was pressed.
return <button
key={ index }
onClick={ (event) => this.buttonToggle(event, stateObj.name) }
value={ stateObj.status } >
{ stateObj.status.toString() }
</button>
And your buttonToggle function could look like this
buttonToggle = (event, name) => {
event.persist();
let { feeling } = this.state;
let newFeeling = [];
for (let index in feeling) {
let feel = feeling[index];
if (feel.name == name) {
feel = {name: feel.name, status: !feel.status};
}
newFeeling.push(feel);
}
this.setState({
feeling: newFeeling,
});
}
Here's a working JSFiddle.
Alternatively, if you don't need to store any more data per feeling than "name" and "status", you could rewrite your component state like this:
feeling: {
alert: false,
calm: false,
creative: false,
etc...
}
And buttonToggle:
buttonToggle = (event, name) => {
event.persist();
let { feeling } = this.state;
feeling[name] = !feeling[name];
this.setState({
feeling
});
}