What is the difference between the two syntax?
setValues(values => ({
...values, [event.target.name]: event.target.value
}))
setValues({
[event.target.name]: event.target.value
})
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
the 'values' parameter contains the current values held in state , so by using the spread operator you preserve the values held in the current state and add in new ones.
In the second example you are just setting the state to the event.target.name and overwriting the previously held state.
For example , suppose the app had called setValues three times with three events : event1 , event2 and event3
In the first case you wrote about your state would be { event1, event2, event3 }. in the second case your state would be { event3 }
Related
this.state = { isOpen: false };
onClickHandler() {
this.setState(currentState => ({
isOpen: !currentState.isOpen
}));
}
There is only one state here,isOpne,but when i set a state ,there i see currentState, what does this means
To calculate new state using the current state, you can very well do:
this.state = { isOpen: false };
onClickHandler() {
this.setState(currentState => ({
isOpen: !this.state.isOpen
}));
}
However this is bad practice as mentioned in docs:
State Updates May Be Asynchronous. 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.
Thus when we need to calculate next state from the current state, the setState provides access to the current state as setState(myCurrentState => {...});. You can even access props as the second parameter like setState((myCurrentState, myProps) => {...});.
So in your case currentState simply refers to your component state at the given moment just before the state update that's going to happen.
what does this means?
If you go to the docs there you can find that there are two ways to update the state.
Via using object way
Via passing a function.
1.
With this you need to pass just the property of the state object to update. like:
this.setState({isOpen: !this.state.isOpen});
2.
In this case you are naming it as currentState it refers to the previous state, which is not yet updated.
this.setState(currentState => ({ // <---currentState is named as prevState in docs
isOpen: !currentState.isOpen
}));
You can think of it as this.state.
in above example currentState is previous state which you have used before when you have multiple items like many users list and want to compare and want to neglate some of them with true false then you can use but for toggle state you can simply use below code:
this.state = { isOpen: false };
onClickHandler() {
this.setState({
isOpen: !this.state.isOpen
});
}
I want to refresh my react table after new data is received. I was expecting I trigger this when I change state, however it doesnt work.
Below is state and the update function:
this.state = {
switchListSelected: [],
switchListData: [],
interfaceStatusData: [],
interfaceErrorsData: []
}
updateParentState(data, element){
this.setState(prevState => {
return prevState[element].push(data)
}
}
You are using setState wrong. You should call setState with the new state (or an updater function which returns the new state) and optionally a callback which will be called when the update is done. You can check the usage of setState in the react docs here.
In your example the updateParentState function should look like this:
updateParentState = (data, element) => {
this.setState({
...this.state,
[element]: [...this.state[element], data]
})
}
Note that the state of a component should never be mutated directly. Hence the creation of a new array with the spread operator instead of Array.push which mutates the array.
2 issues here :
When using setState you need to return an object of the state's attributes to update, here you return the result of prevState[element].push(data) (the array length).
You are mutating the array by using Array.push(), you need to use immutable pattern updates to correctly trigger a render with your updated state.
This should work for your case :
this.setState(prevState => ({
[element]: [...prevState[element], data],
}));
According to the docs, React batches setState if it is provided with a callback
this.setState(prevState => {value: prevState + 1 })
Now, assume we have an instance method that does several setState calls
reset() {
this.setState(prevState => ({value: prevState.initialValue}));
this.setState({initialValue: null});
}
Since we don't need access to state values in the second setState, we don't have to use functional setState. In this situation, does React still batch the functional setState at a later point in time (and potentially execute the object setState first)? Or would it maintain the execution order?
Both setState with a function argument (updater) and with an object argument will apply changes to the state object synchronously. The point is that it applies changes not to the this.state object but to the pending 'next' state object (this is my terminology, not from docs). And updater gives us the ability to access this pending 'next' state we're updating.
Consider this example:
// this.state.value === 0
this.setState({ value: this.state.value + 1 });
// pendingState.value === 1
this.setState(pendingState => ({ value: pendingState.value + 1 }));
// pendingState.value === 2
this.setState(pendingState => ({ value: pendingState.value + 2 }));
// pendingState.value === 4
this.setState({ value: this.state.value + 1 });
// pendingState.value === 1
Hopefully this helps. Same example in codesandbox: https://codesandbox.io/s/2p6j2mxnyj
I have refereed this , this and this link to find solution but none of them work for me.
I have decleared state with array type and other state with null.
this.state = { from: '', to: '',journeyDate: '',searchDetails: [] }
As user fill up search form with source city , destination city and journey date I set these state like below .
let from = this.state.from;
let to = this.state.to;
let journeyDate = moment(this.state.journeyDate).format('YYYY-MM-DD');
final step to push these all variables into searchDetails array state. for that I have tried below options but none of them worked.
OPTION 1
this.setState({ searchDetails: [...this.state.searchDetails, from] });
OPTION 2
this.setState(prevState => ({
searchDetails: [...prevState.searchDetails, from]
}))
OPTION 3
let newState = this.state.searchDetails.slice();
newState.push(from);
this.setState({
searchDetails: newState
});
console.log('final state is : ' + this.state.searchDetails);
every time console log remains empty.
any advice ?
Actually setState is an asynchronous method. That means right after writing setState, you cannot expect the state to be changed immediately. So console.log right after setState may show you last state instead of new state. If you want to log the updated state then use the callback of setState which is called when state is updated like this
this.setState({ searchDetails: [...this.state.searchDetails, from] }, () => {
console.log(this.state.searchDetails)
});
Try :
this.setState({
searchDetails: newState // use any of your 3 methods to set state
},() => {
console.log('final state is : ' + this.state.searchDetails);
});
setState() does not always immediately update the component. It may
batch or defer the update until later.
This makes reading this.state
right after calling setState() a potential pitfall.
Instead, use
componentDidUpdate or a setState callback (setState(updater,
callback)), either of which are guaranteed to fire after the update
has been applied. If you need to set the state based on the previous
state, read about the updater argument below.
For More Detail, Please read : https://reactjs.org/docs/react-component.html#setstate
I was checking the ReactJS tutorial at https://reactjs.org/docs/state-and-lifecycle.html and got confused at following point:
When we want to update the current state based on previous state we should invoke a variant of setState which takes a function
this.setState(function(prevState, props) {
return {
counter: prevState.counter + props.increment
};
});
Now my question is who will invoke this function now with previous state ? As in if we call the setState directly with values we know that we have triggered the workflow to set the state to value. However in this case, who will invoke this method and how does it know what are the params to pass as this is a dynamic method ?
setState function will call the function.
For Example (Not he actual setState function just to show the concept)
var setState = function(param) {
var newState;
if(typeof param === 'function') {
newState = param(prevState); // run function that passed and get the returned object
// set new state with newState
}
else {
newState = param; // use passed object
}
// set new state with newState
}
setState(function(prevState) { return { some: 'Value' }; });
setState({ some: 'Value'});
The current signature of setState
setState({state_name : value})
setState(nextState, callback)
setState(callback)
There are some points to remember while using setState
There is no guarantee that this.state will be immediately updated, so
accessing this.state after calling this method may return the old
value.Because React may batch multiple setState() calls into a single update for performance.
e.g. Below one is wrong as there is no guarantee that this.state.counter is updated one.
assuming count=1 initially.
this.setState({
counter: this.state.counter + 1
});
this.setState({
counter: this.state.counter + 1
});
counter =1 and not 3 as
It’s safe to assume that setState is asynchronous.
To fix it, use other form of setState() that accepts a function(callback) rather than an object
When a function is provided to setState, React will be called it at some point in
the future (not synchronously). It will be called with the up to date
component arguments (state, props, context).
Using third signature
assuming count=1 initially.
this.setState((state)=>({counter: state.counter + 1}))
this.setState((state)=>({counter: state.counter + 1}))
counter = 3