forked from facebook/react
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix: Passive effect updates are never sync (facebook#21215)
I screwed this up in facebook#21082. Got confused by the < versus > thing again. The helper functions are annoying, too, because I always forget the intended order of the arguments. But they're still helpful because when we refactor the type we only have the change the logic in one place. Added a regression test.
- Loading branch information
Showing
1 changed file
with
81 additions
and
0 deletions.
There are no files selected for viewing
81 changes: 81 additions & 0 deletions
81
packages/react-reconciler/src/__tests__/ReactUpdatePriority-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
let React; | ||
let ReactNoop; | ||
let Scheduler; | ||
let useState; | ||
let useEffect; | ||
|
||
describe('ReactUpdatePriority', () => { | ||
beforeEach(() => { | ||
jest.resetModules(); | ||
|
||
React = require('react'); | ||
ReactNoop = require('react-noop-renderer'); | ||
Scheduler = require('scheduler'); | ||
useState = React.useState; | ||
useEffect = React.useEffect; | ||
}); | ||
|
||
function Text({text}) { | ||
Scheduler.unstable_yieldValue(text); | ||
return text; | ||
} | ||
|
||
test('setState inside passive effect triggered by sync update should have default priority', async () => { | ||
const root = ReactNoop.createRoot(); | ||
|
||
function App() { | ||
const [state, setState] = useState(1); | ||
useEffect(() => { | ||
setState(2); | ||
}, []); | ||
return <Text text={state} />; | ||
} | ||
|
||
await ReactNoop.act(async () => { | ||
ReactNoop.flushSync(() => { | ||
root.render(<App />); | ||
}); | ||
// Should not have flushed the effect update yet | ||
expect(Scheduler).toHaveYielded([1]); | ||
}); | ||
expect(Scheduler).toHaveYielded([2]); | ||
}); | ||
|
||
test('setState inside passive effect triggered by idle update should have idle priority', async () => { | ||
const root = ReactNoop.createRoot(); | ||
|
||
let setDefaultState; | ||
function App() { | ||
const [idleState, setIdleState] = useState(1); | ||
const [defaultState, _setDetaultState] = useState(1); | ||
setDefaultState = _setDetaultState; | ||
useEffect(() => { | ||
Scheduler.unstable_yieldValue('Idle update'); | ||
setIdleState(2); | ||
}, []); | ||
return <Text text={`Idle: ${idleState}, Default: ${defaultState}`} />; | ||
} | ||
|
||
await ReactNoop.act(async () => { | ||
ReactNoop.idleUpdates(() => { | ||
root.render(<App />); | ||
}); | ||
// Should not have flushed the effect update yet | ||
expect(Scheduler).toFlushUntilNextPaint(['Idle: 1, Default: 1']); | ||
|
||
// Schedule another update at default priority | ||
setDefaultState(2); | ||
|
||
// The default update flushes first, because | ||
expect(Scheduler).toFlushUntilNextPaint([ | ||
// Idle update is scheduled | ||
'Idle update', | ||
|
||
// The default update flushes first, without including the idle update | ||
'Idle: 1, Default: 2', | ||
]); | ||
}); | ||
// Now the idle update has flushed | ||
expect(Scheduler).toHaveYielded(['Idle: 2, Default: 2']); | ||
}); | ||
}); |