Why does this expression only overrides other properties from the array?
const toggleComplete = (id) => {
const updatedTodos = todos.map((todo) =>
todo.id === id ? todo.completed = !todo.completed : todo
);
setTodos(updatedTodos);
}
With the previous code, todos array only contains the field completed and deletes all other fields.
const toggleComplete = (id) => {
const updatedTodos = todos.map((todo) => {
if (todo.id === id) {
todo.completed = !todo.completed;
}
return todo;
});
setTodos(updatedTodos);
}
While with this code all the array fields stay the same and only changes the completed field, which is the expected behaviour.
3
Answers
The result of
.map()
is entirely based on what the callback function returns. In the second example it’s always returning thetodo
object. But in the first example it’s returning this:This conditionally returns either the whole
todo
object or the result of this expression:The result of an assignment expression is the value which was assigned and only that value. So while this expression is performing an assignment which modifies the
todo
object, that’s of little consequence because that object isn’t returned so.map()
doesn’t use it for anything. It only uses the returned value.This is reminiscent of a common misuse of the
.map()
operation. It’s meant to project an array into a new array, it is not meant for looping over an array to modify something in that array..forEach()
or a simplefor
loop would be used for that.As an aside… I recommend not using either approach in React like this. While this is creating a new array to set state, just before doing so it’s also mutating state.
Don’t assign properties on
todo
at all. Instead, return from the.map()
callback a new object:Because in the first code you are actually returning ‘todo.completed’ if ‘todo.id’ is the same as ‘id’.
In a code example you are basically doing this with the ternary operator:
You might want to read about ternary operator https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator
Let me correct first code based on your expected output, it will be self explanatory then,
If you still don’t get it, here’s the explanation: when you don’t provide curly braces in fat-arrow functions, it will simply return the result of the expression you write (in your case it will always be
true
), so it was replacing the object in the array.In the second part you’re toggling the
todo.completed
and then returning thetodo
, so it is working fine.