In a React functional component with the useState
hook I don't know how to run multiple async operations without having conflict on the final result.
If the initial state is an object and every async operation performs a change on a given key, it's possible to use the spread operator in order to set a new state. Example:
const [oldState, setNewState] = React.useState({ /* something */ });
const asyncOperation = async () => {
await somethingAsync();
setNewState({
...oldState,
key: 'newValue',
});
};
The problem emerges when more of those operations run in the same time: the oldState
used during setNewState
may be changed by the end of another async function, but some updates of the state may be lost when the last async operation performs his setNewState
since the reference to oldState
can point to an old version of the variable.
Here's a demo: try to click every button in a row and, in the end, some of them will (probably) result still loading.
How can I avoid this problem without leaving react hooks?
TL;DR: useState is an asynchronous hook and it doesn't change the state immediately, it has to wait for the component to re-render.
React useState hook is asynchronous!
This WORKS, but you should avoid it. Why? Because React's useEffect hook expects a cleanup function returned from it which is called when the component unmounts. Using an async function here will cause a bug as the cleanup function will never get called.
The answer: They're just queues setState , and React. useState create queues for React core to update the state object of a React component. So the process to update React state is asynchronous for performance reasons. That's why changes don't feel immediate.
You could possibly use a React Ref to store the state of the state variable. Then update the state variable with the react ref. This will render a page refresh, and then use the React Ref in the async function.
This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. Much like setState in Class components created by extending React.Component or React.PureComponent, the state update using the updater provided by useState hook is also asynchronous, and will not be reflected immediately.
This is a way to “preserve” some values between the function calls — useState is a new way to use the exact same capabilities that this.state provides in a class. Normally, variables “disappear” when the function exits but state variables are preserved by React.
During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState). The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.
For async operations, you need to make use of the previous state using the updater function.
setNewState((previousState) => ({
...previousState,
key: 'newValue',
}));
In here, oldState
is != previousState
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With