For objects you can use the spread operator to use prevState within your setState call.
const [object, setObject] = useState({
firstKey: '',
secondKey: '',
});
setObject((prevState) => ({
...prevState,
secondKey: 'value',
}));
// object = {
// firstKey: '',
// secondKey: 'value',
// }
The snippet below show an example of using prevState for setting the state of an object.
const {useState} = React;
const Example = ({title}) => {
const initialState = {
firstKey: 'empty',
secondKey: 'empty',
thirdKey: 'not empty',
}
const [object, setObject] = useState(initialState);
const withPrevState = () => {
setObject((prevState) => ({
...prevState,
secondKey: 'not empty',
}));
}
return (
<div>
<h5>Updates Second key to 'not empty'</h5>
<p>First key: {object.firstKey}</p>
<p>Second key: {object.secondKey}</p>
<p>Third key: {object.thirdKey}</p>
<button onClick={withPrevState}>
Update with prevState
</button>
<button onClick={() => {setObject({secondKey: 'not empty'})}}>
Update without prevState
</button>
<button onClick={() => {setObject(initialState)}}>
Reset
</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
Answer from ppak10 on Stack OverflowFor objects you can use the spread operator to use prevState within your setState call.
const [object, setObject] = useState({
firstKey: '',
secondKey: '',
});
setObject((prevState) => ({
...prevState,
secondKey: 'value',
}));
// object = {
// firstKey: '',
// secondKey: 'value',
// }
The snippet below show an example of using prevState for setting the state of an object.
const {useState} = React;
const Example = ({title}) => {
const initialState = {
firstKey: 'empty',
secondKey: 'empty',
thirdKey: 'not empty',
}
const [object, setObject] = useState(initialState);
const withPrevState = () => {
setObject((prevState) => ({
...prevState,
secondKey: 'not empty',
}));
}
return (
<div>
<h5>Updates Second key to 'not empty'</h5>
<p>First key: {object.firstKey}</p>
<p>Second key: {object.secondKey}</p>
<p>Third key: {object.thirdKey}</p>
<button onClick={withPrevState}>
Update with prevState
</button>
<button onClick={() => {setObject({secondKey: 'not empty'})}}>
Update without prevState
</button>
<button onClick={() => {setObject(initialState)}}>
Reset
</button>
</div>
);
};
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
In order to use Maps, you'll need to clone it before manipulating the values. Otherwise, it's mutating the original Map and React doesn't handle mutatable state.
const handleChange = useCallback(({ target: { name, checked } }) => {
setCheckbox(prevState => {
return new Map(prevState).set(name, checked);
});
}, []);
Updated Working Example:
How to Update State Based on Previous State?
The Role of useEffect in Tracking State Changes
Videos
Might be silly question, but I want to be sure I understand this. Example of incorrectly updating state using useState hook
I'm wondering if in this part of Todo tutorial state was updated incorrectly?
const submitTodoHandler = (e) => {
e.preventDefault();
setTodos([
...todos,
{ text: inputText, completed: false, id: Math.random() * 1000 },
]);
};Or should it be like this:
const submitTodoHandler = (e) => {
e.preventDefault();
setTodos((prevTodos) => [
...prevTodos,
{ text: inputText, completed: false, id: Math.random() * 1000 },
]);
};If you need see whole code, I uploaded it on Github - here
Which one is it?
First of all, you can see the official explanation here.
In this case, I somehow access the previous count value.
You are not somehow accessing the previous count value. If you use a functional update and give a callback function to the setter, it returns the previous state to you and you use this value in your callback function.
setCount expects now a function
Since you provide a function, it can use it.
setCount is now run asynchron
Actually, no. It is not an asynchronous function. It just provides the previous state and you use it. State setters are not asynchronous, state update is.
Where is this function coming from?
Where is prevCount coming from?
Already answered.
When i run this, what is put into prevCount?
You provide what do you want to be set the new state there. In your example, you want to increment count by 1, so you are providing + 1
Here is a naive explanation for this logic. Just a naive one. I'm adding this to exemplify the callback logic, this is not related to React's setState.
let state = 5;
function setState(val) {
if (typeof val === "function") {
return val(state);
}
return val;
}
const stateWithFunctionalUpdate = setState(prev => prev + 1);
const stateWithNormalUpdate = setState(9);
console.log(stateWithFunctionalUpdate);
console.log(stateWithNormalUpdate);
Maybe this example would be suitable for mimicking the React's state setting logic. Again, just a naive approach.
let state = 5;
function setState(val) {
if (typeof val === "function") {
state = val(state);
} else {
state = val;
}
}
setState(9);
setState(prev => prev + 1);
console.log("state", state);
Let's look at the real implementation of useState (without typings):
export function useState(initialState) {
return useReducer(
basicStateReducer,
// useReducer has a special case to support lazy useState initializers
initialState
);
}
Well, it just uses useReducer behind the curtains. It sets the initial state and uses basicStateReducer which is:
function basicStateReducer(state, action) {
return typeof action === "function" ? action(state) : action;
}
Like our naive approach, it looks for the type of the action and behaves according to that. Finally, this is what useReducer returns:
return [workInProgressHook.memoizedState, dispatch];
So, at the end of the day, if we provide a function to useState, it takes it and then run it on our state and returns the value back.
Here is my opinion how i understand:
In this case, I somehow access the previous count value. -> setCount will check param, if the param is a callback it will call that call back and pass previous state for param. Result of call back will be next state.
setCount expects now a function -> yes, function handle you logic and return next state.
setCount is now run asynchron -> this function is synchron but after it return result. The hook for setCount will dispatch event to update the next state
Where is this function coming from? -> your can do anything in function as long as param will be current state and return a next state.
Where is prevCount coming from? -> will be passed when call setCount(it's get from current state).
When i run this, what is put into prevCount? -> current state of setCount.
=> Example for how to pass a value or a call back to setCount here: useState hook, setState function. Accessing previous state value