-
Notifications
You must be signed in to change notification settings - Fork 46.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Batching update in react-hooks #14259
Comments
This appears to be normal React behavior. It works the exact same way if you were to call React currently will batch state updates if they're triggered from within a React-based event, like a button click or input change. It will not batch updates if they're triggered outside of a React event handler, like a I think there's plans long-term to always batch events, but not sure on the details. |
Yeah, this isn’t different from behavior in classes. You can opt into batching with |
when we are using this.setState({a: 4, b: 5}); but when we are using useState hooks, set state functions called seperately: setA(4);
setB(5); I think it is necessary to have automatic batching for useState hooks. |
@smmoosavi : no, React handles both |
if the event handler is an async function, they will not be batched up. more real-world example: https://codesandbox.io/s/8lp7y5wj09 const onClick = async () => {
setLoading(true);
setData(null);
// batched render happen
const res = await getData();
setLoading(false);
// render with bad state
setData(res);
};
console.log("render", loading, data); output:
|
@smmoosavi : yes, that matches everything I've said already. React wraps your event handlers in a call to |
Is there a way though to batch state updates in async calls? |
@rolandjitsu : Per Dan's comment earlier:
|
@markerikson sorry, I did not pay attention to the comments and I ignored them once I saw |
To solve this problem I use |
Yep, using the reducer is recommended for anything other than a trivial update. |
You can replace |
Spent some time at work today trying to find a good solution to this. Ended up merging my two states ( |
I find myself running into a lot of use cases where two state values are usually completely separate, but occasionally might be updated at the same time. |
Hey, what about doing it with a batch wrapper call, like Redux does it now: const [ state, dispatch, batch ] = useReducer(reducer, initialState);
batch(() => {
dispatch(..);
dispatch(..);
// etc..
}) ? |
@nmain import React from 'react';
import ReactDOM from 'react-dom';
import { install } from 'batched-hook';
// `uninstall` function will restore default React behavior.
const uninstall = install(React, ReactDOM); |
Thanks, I'll take a look into that. 👍 |
@gaearon |
@smmoosavi this was explained already, inside |
I mean programmatically. something like this: function inBatchedMode() {
return workPhase !== NotWorking
} |
@gaearon So you make mention that the only way to make sure that multiple calls to I assume yes since is it pre-fixed with |
@rzec-r7 : we actually started using this in React-Redux v7, because Dan explicitly encouraged us to. I believe one of his comments was "Half of Facebook depends on this, and it's the most stable of the 'unstable' APIs". |
@gaearon any insight on why batching is still considered |
This is also likely to happen when the state is changed within a window event. |
How do I batch updates with a custom reconciler? Using the lib: https://github.com/inlet/react-pixi and |
Batching is reconciler-dependent. That's why React-Redux has to semi-depend on importing |
In my case I had the same global store to update and delete from various setTimeouts, in that case, setSomevariable wasn't batching.. the fix which worked for me was using the prev state of Actual working is confusing me..but its working ;) |
@markerikson What a useful post! Thank you. I wonder what happens when a setState() is called inside the setTimeout() handler. The setTimeout is placed inside a new Promise() and the last statement of the handler is a call to resolve() the promise. There is also a then() to run after the promise is fulfilled. At what moment of time, will React re-render the component? Thanks |
@bhaidar : earlier this year I wrote an extensive post on A (Mostly) Complete Guide to React Rendering Behavior, specifically to answer questions like yours :) I'd encourage you to read through it in detail. |
Thanks @markerikson I will surely read it. |
Am I the only one expect React.useCallback should do state changes in a single batch/transaction for me ? |
@dcheung2 100% agree. There may be some down sides, but coding in React I feel like it's more intuative if useCallback and useEffect did everything in a batch. |
@acidic9 React.useCallback(async ()=>{
setState1(1);
setState2(1); // likely batched, if
await Promise.resolve(2);
setState1(3); // won't batched
setState2(3); // won't batched
await Promise.resolve(4);
setState1(5); //non batched
await Promise.resolve(6);
setState2(7); // non batched
}, []); but at least React.useCallback could mitigate half of it, if they are going to it in the legacy mode without using anything unstable API. Or it may helps some eslint rule to detect the problem. I believe they want the blocking/concurrent mode in new React will eventually fix the cause. |
Does anyone know if the new automatic batching feature in React 18 works also with several Usually, I only dispatch once when something happens in my component, but some people also do something like: dispatch({ type: "ACTION_1" });
dispatch({ type: "ACTION_2" }); Would these be batched automatically, resulting in a single render? |
@dani-mp : |
I just got hit by this footgun. A codependent state update was working fine while being called from events. But the first time I called it from a resolved promise, it started crashing. IMO this is a surprising behavior. It should work the same in both situations. |
@panta82 the existing behavior is well documented. But, per reactwg/react-18#21 , multiple updates in a single event loop tick outside of React's original event handling (ie, in a |
@markerikson This is a very positive change! Exactly what's needed. As for the documentation, I browsed through the |
Do you want to request a feature or report a bug?
bug + improvement
What is the current behavior?
Sometimes state updates caused by multiple calls to
useState
setter, are not batched.sandbox1: https://codesandbox.io/s/8yy0nw2m28
sandbox2: https://codesandbox.io/s/1498n44yr3
Step to reproduce: click on
increment all
text and check the consolediff:
console1:
console2:
What is the expected behavior?
Render function should be called once after multiple calls of
setState
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
react: 16.7.0-alpha.2
The text was updated successfully, but these errors were encountered: