Comments (10)
Thanks for the detailed investigation, @phryneas and @jerelmiller! The repro you put together (https://github.com/react-native-community/reproducer-react-native) is really helpful in understanding the root cause.
It seems the slowness is related to how use interacts with promises generated from multiple user input events within a single act call, specifically when the original value updates before the deferred value. This is interesting behavior, and I'd be glad to help troubleshoot further.
Here are some additional thoughts based on your findings:
Consider alternative testing approaches: While act is useful for simulating user interactions, could the test be rewritten to avoid the problematic combination of act and multiple user input events within it? Perhaps separate act calls for each user input could be explored.
Investigate the root cause within use: If the issue lies within the use hook itself, diving deeper into the implementation might reveal areas for optimization, especially regarding handling multiple promises triggered by user interactions.
I'm happy to assist in any way possible to move this issue forward. Perhaps we can discuss potential solutions or debugging strategies in a follow-up comment or collaboratively on a pull request if a code change is identified.
from react.
@eps1lon I also updated the README of that repo to include the details and reproduction steps.
from react.
Added context: this seems to be triggered by user.type(input, "ab"));
- changing it to user.type(input, "a"));
makes everything fast again.
So my working theory is that the order of operation
- user types
"a"
useDeferredValue
starts a transition and a query for"a"
creates a promise that is passed intouse
- user types
"b"
useDeferredValue
starts a transition and a query for"ab"
creates a new promise that is passed intouse
seems to cause this - maybe because use
still latches onto the first promise and ignores the second, semantically different, promise.
from react.
I'll add to this some additional findings. @phryneas's theory is close, but it seems this only occurs when the original value is updated before the deferred value. Everything stays fast if the deferred value only lags behind one update from the original. In other words, if I log the two values, the fast execution has this timeline:
{ value: 'a', deferredValue: '' }
{ value: 'a', deferredValue: 'a' }
{ value: 'ab', deferredValue: 'a' }
{ value: 'ab', deferredValue: 'ab' }
which I can simulate with await user.type('a'); await user.type('b')
(using the userEvent
library).
But it gets slow with this timeline (i.e. the await user.type('ab')
case):
{ value: 'a', deferredValue: '' }
{ value: 'ab', deferredValue: '' }
{ value: 'ab', deferredValue: 'ab' }
The promise attached to the empty string is resolved by the time we simulate the ab
keyboard input and we only create a single promise when deferredValue
gets updated to ab
, so I can confirm we aren't accidentally creating a bunch of new promises that use
can't keep up with.
I'm still working to see if I can create an isolated reproduction without Apollo or its test suite. Will report back if I have success.
from react.
Update: It seems the issue lies in the way act
works with the user event library, specifically typing multiple characters. If I replace this line:
await act(() => user.type('ab'))
with
await user.type('ab')`
I see act warnings, but the test goes back to being fast. Seems there is some combination of things here that cause something to spiral out of control. Here are all the things that work to speed up the test again and exhibit the expected behavior:
- Removing
act
around theuser.type('ab')
- Typing a letter at a time (i.e.
await act(() => user.type('a')); await act(() => user.type('b'))
) - Switching
React.use
for our custom__use
polyfill
If the swap of React.use
didn't do anything, I'd be inclined to say the the problem was with the user event library, but perhaps the combination of act
and use
is doing something odd here 🤔.
I'll continue working on a reproduction in a test environment. I was unable to reproduce using a running app in the browser which is a good thing.
from react.
Alright I was able to get a reproduction together that demonstrates the issue in a test. Check out my reproduction here: https://github.com/jerelmiller/react-use-reproduction/blob/master/src/App.test.tsx
Run npm test
to run the test and you'll see it timeout. I've annotated that test file with comments that describe how to get the test to pass without timing out. This structure is consistent with what we are seeing in Apollo Client's codebase. The test will pass eventually if you increase the timeout high enough, but there is no reason it shouldn't pass within the default 5s window.
from react.
@RacketyWater7 This is a bug report in the React repo.
We know how to work around this and do not need assistance with that.
Trying to work around the problem we are reporting here would be counterproductive to the the intent of this issue - identifying the bug in React, reproducting it and getting it fixed.
We literally spent two days to get a reliable isolated reproduction of this bug.
from react.
I could narrow it down a bit further by replacing user.type
with manual event dispatches.
This pattern is problematic in combination with use
and useDeferredValue
:
await act(async () => {
fireEvent.change(input, { target: { value: "a" } });
await new Promise((resolve) => setTimeout(resolve, 1));
fireEvent.change(input, { target: { value: "ab" } });
});
If you skip the act
, it works as expected, if you skip the setTimeout
between the events it also works as expected.
from react.
@phryneas Can you pack this into a minimal, cloneable repro? Ideally with clear instructions how to repro and what the expected vs actual behavior is for each case.
from react.
@eps1lon we updated the repro that @jerelmiller linked above: https://github.com/jerelmiller/react-use-reproduction/blob/master/src/App.test.tsx
For running it, just clone it and run yarn install
followed by yarn test
-- the file with the reproduction is only 100 lines and half of them are comments :)
from react.
Related Issues (20)
- [React 19]
- ..
- [DevTools Bug]: 5.2.0 is not available for Firefox HOT 2
- [DevTools Bug] getCommitTree(): Invalid commit "1" for root "445". There are only "1" commits.
- [eslint-plugin-react-hooks] Missing type declarations HOT 2
- [React 19]
- Bug: useEffect is triggered even if the array as dependency variable wasn't changed. HOT 4
- [DevTools Bug]: React Devtools not working neither on vite or cra project HOT 5
- ..
- Bug: Error Recovery Mechanism Overwriting Initial Rendering Errors in Concurrent Mode HOT 1
- Bug: Empty `style={}` object values cause hydration warnings in React 18.3.1 - Includes solution
- [React 19] Cannot assign to readonly property HOT 8
- Unexpected Initial State Jump in 'useEffect" with 'setTimeout' and State Dependencies HOT 3
- React[19] Module '"react"' has no exported member 'useActionState'. HOT 2
- Bug: effect runs with stale state values outside of Concurrent React HOT 1
- Feature Request: ESLint hooks rule for accessing previous state when deriving new state
- Bug: Weird Behavior of useCallback() hook When Variables or States Are defined before and after the Callback (ES5) HOT 5
- Bug: div: `ref` is not a prop HOT 2
- Bug: useFormStatus pending state is reset when component state is updated HOT 3
- [React 19] TEST HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from react.