Solvedreact easy state batching eventlistener breaks input editing with React 16.9
✔️Accepted Answer
Quite a critical bug imho. Repro at https://codesandbox.io/s/vigorous-grothendieck-63ybi.
Typing into the middle of <input>
resets the cursors to the end. Is this module monkey-patching React given that the issue shows without wrapping a component in view
? I would strongly suggest not doing that for forward compat cases like this.
Other Answers:
@solkimicreb I'd love to help with this but I'm going to need your help.
The first thing I wonder is if we can get rid of unstable_batchedUpdates
altogether.
Is the monkey-patching of scheduler.js
used to:
- Solve the stale-props/zombie-children* problem? If it is not, how does
react-easy-state
solve it? - Batch mutations together (like the old mobx
transaction
)? - Any other reason?
* There's an excellent article of Kai Hao (@kevin940726) about the stale-props/zombie-children problem of state managers. Following that, Paul Henschel (@drcmda) introduced an alternative solution on Zustand based on an incremental id which may be interesting: pmndrs/zustand#65
The React dev team has released the documentation of React Concurrent. It states this about unsafe_batchedUpdates
:
*: Legacy mode has automatic batching in React-managed events but it’s limited to one browser task. Non-React events must opt-in using unstable_batchedUpdates. In Blocking Mode and Concurrent Mode, all setStates are batched by default.
https://reactjs.org/docs/concurrent-mode-adoption.html#feature-comparison
I've done some tests and it works great. It looks like unsafe_batchedUpdates
is not needed at all in Concurrent mode:
https://codesandbox.io/s/react-easy-state-batch-bug-v5yne
I had to do the tests in the DOM because the testing library of React has not been updated yet to support Concurrent mode.
It also works on the upcoming Blocking mode, which could be adopted as soon as Concurrent mode is released:
For older codebases, Concurrent Mode might be a step too far. This is why we also provide a new “Blocking Mode” in the experimental React builds. You can try it by substituting createRoot with createBlockingRoot. It only offers a small subset of the Concurrent Mode features, but it is closer to how React works today and can serve as a migration step.
I wonder how long would it take to the React team to release Concurrent mode in the stable version, tho.
So on the other hand, the way I was thinking to solve this is using an async scheduler. The library @nx-js/queue-util
(by @solkimicreb as well) works fine.
This is the same codesandbox with tests but with React version 16.11. Without scheduler, but with the async scheduler fix. The<Input>
component works fine again.
https://codesandbox.io/s/react-easy-state-batch-bug-async-scheduler-6q2dt
Miklos, what do you think? What is the advantage of monkey patching the native elements over using an async scheduler and why did you do that instead of this in the first place?
The package is moved to @risingstack/react-easy-state v6.2.0 of the new package includes the fix for this issue, please move to that package
Hello,
We've upgraded to React 16.9 (from 16.8) and it breaks our controlled inputs because of something inside react-easy-state. It is fixed as soon as I remove the batching of eventlisteners here: https://github.com/solkimicreb/react-easy-state/blob/1aeb0ddbc386a36adc3758a12d740989e99655a6/src/scheduler.js#L87
What breaks?
Expected result: "Hello dear world".
Actual result: "Hello dworldear"
The cursor moves to the end of the input everytime you add a character.
Here's how to recreate:
OR, with hooks:
Why is it related to react-easy-state?
view
though.We noticed a comment a few lines above😄
// this should be removed when React's own batching is improved in the future
, perhaps React 16.9 batching is improved now?Thanks for an otherwise great state management tool!