With this code, I am able to successfully use setState
on a simple object – when I click on "Joey" the name changes to "Igor".
class Card extends React.Component {
myFunc = () => {this.props.change('Igor')};
render() {
return (
<p onClick={this.myFunc}>{this.props.name}</p>
)
}
}
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = { name: "Joey" }
}
toggle = (newname) => {
this.setState((prevState, props) => ({
name: newname
}));
}
render() {
return (
<Card change={this.toggle} name={this.state.name} />
);
}
}
But with this code, which has multiple objects nested in an array, setState
is either not able to change each name to "Igor" or it must be modified in some way.
class Card extends React.Component {
myFunc = () => {this.props.change('Igor')};
render() {
return (
<p onClick={this.myFunc}>{this.props.name}</p>
)
}
}
class Parent extends React.Component {
constructor(props) {
super(props)
this.state = {
names: [
{
name: "Joey"
},
{
name: "Sally"
},
{
name: "Billy"
},
]
}
}
toggle = (newname) => {
this.setState((prevState, props) => ({
// what can I put here to change the name I click on to "Igor"
}));
}
render() {
const names = this.state.names.map((name, index) => (
<Card key={index} change={this.toggle} {...name} />
))
return (
<div>
{names}
</div>
);
}
}
Even though I know this is not how setState
works, I tried to access name
by passing index
and then writing this.state.names[index].name: newname
. No surprises here, it didn't work.
I have researched and cannot find similar questions on SO about this although I have found a lot of mentions with regards to immutability helpers. But I am still not sure if that is the way to go.
What is the best way to use setState
to modify objects nested in an array?
Have modified your code and the working example can be found here.
The changes can be found here:
toggle = (index, newname) => {
this.setState((prevState, props) => ({
// Return new array, do not mutate previous state.
names: [
...prevState.names.slice(0, index),
{ name: newname },
...prevState.names.slice(index + 1),
],
}));
}
render() {
const names = this.state.names.map((name, index) => (
// Need to bind the index so callback knows which item needs to be changed.
<Card key={index} change={this.toggle.bind(this, index)} {...name} />
))
return (
<div>
{names}
</div>
);
}
The idea is that you need to pass the index into the callback function via .bind
, and return a new state
array with the modified name. You need to pass the index so that the component knows which object to change the name
to newname
.
I would use this for the toggle method:
toggle = (nameYouWantChanged, nameYouWantItChangedTo) => {
this.setState({
names: this.state.names.map(obj =>
obj.name === nameYouWantChanged
? { name: nameYouWantItChangedTo }
: obj
)
})
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With