Reputation: 4684
I am new to react and I want to ask what's the best way to update state, I have some code. I know the code below is not correct as it's setting the state directly.
handlexxx = foo => {
const foos = [...this.state.foos];
const index = foos.indexOf(foo);
foos[index].bar = !foo.bar;
this.setState({ foos });
};
Those two code below which one is better? can some one explain me please!
handlexxx = foo => {
const foos = [...this.state.foos];
const index = foos.indexOf(foo);
foos[index] = { ...foo };
foos[index].bar = !foo.bar;
this.setState({ foos });
};
handlexxx = foo => {
const foos = [...this.state.foos];
const index = foos.indexOf(foo);
foos[index] = { ...foos[index] };
foos[index].bar = !foos[index].bar;
this.setState({ foos });
};
My account got blocked by some down votes questions, the funny thing is I have to re-edit them, even though I already have the accepted answer.I do not understand what's the point to do this.I am so frustrated by this stackoverflow system.
Now, I basically can do nothing but keep editing my questions, and they have all been answered. This is ridiculous !!!
Upvotes: 0
Views: 81
Reputation: 17608
Since your foo
object has an id
property it is better to use .map
method and mix this with spread syntax or Object.assign
, then return the related elements as @Nguyễn Thanh Tú explained. But, if you want to do this with indexes here are the examples.
You can use findIndex
, not indexOf
. Since indexOf
just look for a value, findIndex
accepts a function. Find the index of the item, map the array, then if index matches do the change if it does not match return the unrelated item.
state = {
foos: [
{ id: 1, bar: true },
{ id: 2, bar: false },
{ id: 3, bar: false },
],
};
const foo = { id: 2, bar: false };
const handleState = foo => {
const index = state.foos.findIndex(el => el.id === foo.id );
const newFoos = state.foos.map( ( foo, i ) => {
if ( i !== index ) { return foo };
return { ...foo, bar: !foo.bar };
})
console.log( newFoos );
}
handleState(foo);
Second one. Here, we are using Object.assign
in a tricky way. Instead of mapping the array we use Object.assign
and change the item using its index.
state = {
foos: [
{ id: 1, bar: true },
{ id: 2, bar: false },
{ id: 3, bar: false },
],
};
const foo = { id: 2, bar: false };
const handleState2 = foo => {
const index = state.foos.findIndex(el => el.id === foo.id );
const newFoos = Object.assign( [], state.foos, { [index]: { ...foo, bar: !foo.bar } });
console.log( newFoos );
}
handleState2(foo);
Third one. Without an index, with only .map
and using directly the id
property. We don't need to find an index here, we are just checking with the id
property to find the right item.
state = {
foos: [
{ id: 1, bar: true },
{ id: 2, bar: false },
{ id: 3, bar: false },
],
};
const foo = { id: 2, bar: false };
const handleState3 = foo => {
const newFoos = state.foos.map( el => {
if ( el.id !== foo.id ) { return el };
return { ...el, bar: !el.bar };
})
console.log( newFoos );
}
handleState3( foo );
Upvotes: 0
Reputation: 27594
One classic way to avoid mutations even for complex nested objects is to use JSON.parse(JSON.stringify(COMPLICATED_OBJECT))
. This will return a representation of your object that has no reference to the original object, so you can mutate the copy without affecting the original:
var foos = [
{ id: 1, bar: false },
{ id: 2, bar: false },
{ id: 3, bar: false },
]
var foo = foos[0];
var _foos = JSON.parse(JSON.stringify(foos)).map(f => {
if (f.id === foo.id) f.bar = !foo.bar;
return f;
});
If you run this, you'll see foos
is unchanged but _foos
is updated
At the end of the day, you might want to think about which solution you find most readable, and which solution other developers on your team might find most readable. If you have to return to this code in 3 years, you'll want to be able to read the code off the page without any head scratching.
Upvotes: 1
Reputation: 10179
You should use Array.prototype.map()
method, like this:
handlexxx = foo => {
const foos = this.state.foos.map(f => {
if(foo.id === f.id) return {...f, bar: !f.bar}; // assume that the element has an identifier id
return f;
})
this.setState({ foos });
};
For short, using ternary operator
instead of if-else
statement
handlexxx = foo => {
const foos = this.state.foos.map(f => foo.id === f.id ? {...f, bar: !f.bar} : f
this.setState({ foos });
};
Upvotes: 1