Both works in that case, but you don't need to use that. Just setting the state will be okay:
this.setState({active: false})
But let me explain what if you have nested level of states like:
state = {
foo: {
a: 1,
b: 2,
c: 3
}
}
And when you need to update the foo's c state only, then you'll need to merge the state like:
this.setState({ foo: {
...this.state.foo,
c: 'updated value'
}})
So, the spread syntax merges object with later object. It's similar to Object.assign.
Answer from Bhojendra Rauniyar on Stack OverflowBoth works in that case, but you don't need to use that. Just setting the state will be okay:
this.setState({active: false})
But let me explain what if you have nested level of states like:
state = {
foo: {
a: 1,
b: 2,
c: 3
}
}
And when you need to update the foo's c state only, then you'll need to merge the state like:
this.setState({ foo: {
...this.state.foo,
c: 'updated value'
}})
So, the spread syntax merges object with later object. It's similar to Object.assign.
The second snippet works because React is implicitly doing the spreading for you. Per React's documentation for setState:
You may [...] pass an object as the first argument to
setState():setState(stateChange[, callback]). This performs a shallow merge of stateChange into the new state.
Using the spread operator in setState hook
reactjs - setState with spread operator - Stack Overflow
How to use spread operator in setstate react class component
Why use the spread operator when calling 'setState()' in React?
Based upon the name setValues I assume you are referring to functional component state. (useState hook updates don't work quite the same as class-based component's setState lifecycle function)
Using the spread syntax allows for maintaining existing state, i.e. the new update [event.target.name]: event.target.value is merged into current state.
Given state { 'foo': 'bar' }
setValues(values => ({
...values, ['bizz']: 'buzz'
}))
New state { 'foo': 'bar', 'bizz': 'buzz' }
Without spreading in the previous state you are simply overwriting it with just an object {[event.target.name]: event.target.value}, so all previous state is lost.
Given state { 'foo': 'bar' }
setValues({
['bizz']: 'buzz'
})
New state { 'bizz': 'buzz' }
There are actually a couple things going on here. First is the spread syntax, the other is what is called a functional update. Functional updates allow the update to access the current state and make changes. This is a necessity when the next state depends on the previous state, like incrementing counters, and multiple state updates can be queued up during each render cycle.
setCount(count => count +1)
In the case of a form component where each property is an independent piece of state, then the following syntax is ok since each update to a field overwrites the current value:
setValues({
...values,
[fieldName]: fieldValue
})
React may batch multiple setState() calls into a single update for performance.
Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
For example, this code may fail to update the counter:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
We used an arrow function above, but it also works with regular functions:
// Correct
this.setState(function(state, props) {
return {
counter: state.counter + props.increment
};
});
Read more here on their official documentation
Currently I'm doing this:
setContacts([...contacts, { newContact }]);
That results in newContact being added to the end of the contacts array. I'm wondering if I do
setContacts([{newContact }, ...contacts ]);
would newContact be added to the beginning of the contacts array, which is what I want?
As per the documentation:
Never mutate
this.statedirectly, as callingsetState()afterwards may replace the mutation you made. Treatthis.stateas if it wereimmutable.
- reactjs.org/docs/react-component.html#state
So, in the example from the tutorial you've mentioned, you wouldn't need to make a copy of the array to update your state.
// GOOD
delTodo = id => {
this.setState({
todos: this.state.todos.filter(...)
})
}
Array.filter method creates a new array and does not mutate the original array, therefore it won't directly mutate your state. Same thing applies to methods such as Array.map or Array.concat.
If your state is an array and you're applying methods that are mutable, you should copy your array.
See more to figure out which Array methods are mutable:
- doesitmutate.xyz
However, if you were to do something like the following:
// BAD
delTodo = id => {
const todos = this.state.todos
todos.splice(id, 1)
this.setState({ todos: todos })
}
Then you'd be mutating your state directly, because Array.splice changes the content of an existing array, rather than returning a new array after deleting the specific item. Therefore, you should copy your array with the spread operator.
// GOOD
delTodo = id => {
const todos = [...this.state.todos]
todos.splice(id, 1)
this.setState({ todos: todos })
}
Similarly with objects, you should apply the same technique.
// BAD
updateFoo = () => {
const foo = this.state.foo // `foo` is an object {}
foo.bar = "HelloWorld"
this.setState({ foo: foo })
}
The above directly mutates your state, so you should make a copy and then update your state.
// GOOD
updateFoo = () => {
const foo = {...this.state.foo} // `foo` is an object {}
foo.bar = "HelloWorld"
this.setState({ foo: foo })
}
Hope this helps.
Why use the spread operator at all?
The spread operator ... is often used for creating shallow copies of arrays or objects. This is especially useful when you aim to avoid mutating values, which is encouraged for different reasons. TLDR; Code with immutable values is much easier to reason about. Long answer here.
Why is the spread operator used so commonly in react?
In react, it is strongly recommended to avoid mutation of this.state and instead call this.setState(newState). Mutating state directly will not trigger a re-render, and may lead to poor UX, unexpected behavior, or even bugs. This is because it may cause the internal state to differ from the state that is being rendered.
To avoid manipulating values, it has become common practice to use the spread operator to create derivatives of objects (or arrays), without mutating the original:
// current state
let initialState = {
user: "Bastian",
activeTodo: "do nothing",
todos: ["do nothing"]
}
function addNewTodo(newTodo) {
// - first spread state, to copy over the current state and avoid mutation
// - then set the fields you wish to modify
this.setState({
...this.state,
activeTodo: newTodo,
todos: [...this.state.todos, newTodo]
})
}
// updating state like this...
addNewTodo("go for a run")
// results in the initial state to be replaced by this:
let updatedState = {
user: "Bastian",
activeTodo: "go for a run",
todos: ["do nothing", "go for a run"]
}
Why is the spread operator used in the example?
Probably to avoid accidental state mutation. While Array.filter() does not mutate the original array and is safe to use on react state, there are several other methods which do mutate the original array, and should not be used on state. For example: .push(), .pop(),.splice(). By spreading the array before calling an operation on it, you ensure that you are not mutating state. That being said, I believe the author made a typo and instead was going for this:
delTodo = id => {
this.setState({
todos: [...this.state.todos].filter(todo => todo.id !== id)
});
};
If you have a need to use one of the mutating functions, you can choose to use them with spread in the following manner, to avoid mutating state and potentially causing bugs in your application:
// here we mutate the copied array, before we set it as the new state
// note that we spread BEFORE using an array method
this.setState({
todos: [...this.state.todos].push("new todo")
});
// in this case, you can also avoid mutation alltogether:
this.setState({
todos: [...this.state.todos, "new todo"]
});
You still don't want to mutate state. So if your state is an object, you'll want to create a new object and set with that. This may involve spreading the old state. For example:
const [person, setPerson] = useState({ name: 'alice', age: 30 });
const onClick = () => {
// Do this:
setPerson(prevPerson => {
return {
...prevPerson,
age: prevPerson.age + 1
}
})
// Not this:
//setPerson(prevPerson => {
// prevPerson.age++;
// return prevPerson;
//});
}
That said, using hooks you often no longer need your state to be an object, and can instead use useState multiple times. If you're not using objects or arrays, then copying is not needed, so spreading is also not needed.
const [name, setName] = useState('alice');
const [age, setAge] = useState(30);
const onClick = () => {
setAge(prevAge => prevAge + 1);
}
What it means is that if you define a state variable like this:
const [myThings, changeMyThings] = useState({cats: 'yes', strings: 'yellow', pizza: true })
Then you do something like changeMyThings({ cats: 'no' }), the resulting state object will just be { cats: 'no' }. The new value is not merged into the old one, it is just replaced. If you want to maintain the whole state object, you would want to use the spread operator:
changeMyThings({ ...myThings, cats: 'no' })
This would give you your original state object and only update the one thing you changed.
Both works in that case, but you don't need to use that. Just setting the state will be okay:
this.setState({active: false})
But let me explain what if you have nested level of states like:
state = {
foo: {
a: 1,
b: 2,
c: 3
}
}
And when you need to update the foo's c state only, then you'll need to merge the state like:
this.setState({ foo: {
...this.state.foo,
c: 'updated value'
}})
So, the spread syntax merges object with later object. It's similar to Object.assign.
The second snippet works because React is implicitly doing the spreading for you. Per React's documentation for setState:
You may [...] pass an object as the first argument to
setState():setState(stateChange[, callback]). This performs a shallow merge of stateChange into the new state.
Many ways to do it, really. Here's one:
this.setState(prevState => (
{appointmentsData: {...prevState.appointmentsData}, newAppt}
));
Though your approach should work too, if you just add the appointmentsData: first. Like so:
this.setState({appointmentsData: {...this.state.appointmentsData, ...newAppt}});
This will spread all the previous values into a new object, plus the one you want to add.
I personally always use the functional way of setting the state when the new one depends on a previous state value, but your way is fine here too.
You should not use spread operator on newAppt. Just go with:
this.setState({ ...this.state.appointmentsData, newAppt});. It seems to me that the spread operator on newAppt is not getting any data for the const.