-
Notifications
You must be signed in to change notification settings - Fork 50.4k
Description
Do you want to request a feature or report a bug?
Maybe not exactly a bug, but it certainly was surprising behavior when I ran into it.
What is the current behavior?
When using a useState hook, it is preferable (and even recommended in the docs about hooks) to use an individual useState hook for each atomic piece of state your component may contain.
This is all well and good, except that setStates are not batched in async code. I was writing a component that used a few different pieces of state, but had some pieces which all needed to be set at more or less the same time, and as a response to an asynchronous action.
I set both pieces of state, and when I went to test it the whole page crashed. It then took me several minutes of debugging to realize why not all of my state was set, despite my handler looking sound: the component was rerendered during the setState call.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:
This is a contrived example, but you can imagine how a real asynchronous method like a web request or other promise-based api could easily lead to the issue: https://codesandbox.io/s/zk1kwlmp4p
In my exact case, a was actually a currentPage string, and b was an object which a child component needed in order to render, which was fetched asynchronously and passed down.
What is the expected behavior?
I'm not here to say that this is necessarily a bug per se, since this has also been true for class components for a long time and hasn't really been an issue. I've been working in react for two years and have never had a problem with class components and async code, for example.
I'm also well aware of possible workarounds, like storing both fields in the same state object, or reordering the setStates such that the render doesn't switch to the new "mode" until the required state has been set. The first simple seems like it's non-idiomatic for hooks, and as for the second, one could imagine that it would become complicated once there are more modes, and the inter-dependencies between different pieces of state get messier.
I could also use the unstable batched updates api, but I don't like the idea of depending on an unstable api, especially in code where I can't easily insulate myself from breaking changes in the api down the line.
I'd just like to point out that this was what to me seemed like a very natural way to write the component, and that the crash caught me entirely by surprise.
I know that it has been mentioned elsewhere that react may move to always batching setStates, and I think this gotcha may increase the impetus to go ahead and do so.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
Any version since hooks were released, independent of browser or operating system.