Repository navigation
fix(VirtualizedList): clear batch timer id on unmount so a Suspense-revived list can schedule updates again - #59123
Conversation
…evived list can schedule updates again
`componentWillUnmount` clears the pending `_updateCellsToRenderTimeoutID`
timer but never resets the field to `null`. The low-priority branch of
`_scheduleCellsToRenderUpdate` only schedules a new batch when the id is
`null`, so the stale id blocks every future low-priority update on that
instance.
Unmount is not final for a class instance that sits inside a Suspense
boundary: when already-mounted content is hidden and later revealed
(the react-freeze pattern used by react-native-screens `freezeOnBlur`),
React calls `componentWillUnmount` and then `componentDidMount` on the
same instance. If a batch timer was pending at the hide, the list comes
back unable to schedule low-priority updates. When the list also had no
items at the hide, `cellsAroundViewport` is `{first: 0, last: -1}` and
the high-priority path (`last >= 0`) cannot recover either, so the render
window stays at `initialNumToRender` no matter how much data arrives.
Reproduced in Jest: a list with `initialNumToRender={12}` that is laid
out empty, frozen, revealed and then given 28 items renders 12 cells
forever. With the id reset it renders all 28.
Changelog: [General] [Fixed] - VirtualizedList: clear the pending batch-update timer id in componentWillUnmount so a list hidden and revived by Suspense (react-freeze / freezeOnBlur) resumes rendering new cells
|
Hi @twelvearrays! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
Summary:
VirtualizedList.componentWillUnmountclears the pending_updateCellsToRenderTimeoutIDtimer but never resets the field tonull. The low-priority branch of_scheduleCellsToRenderUpdateonly schedules a batch when that id isnull, so the stale id blocks every future low-priority update on the instance.Unmount is not final for a class instance inside a Suspense boundary. When already-mounted content is hidden and later revealed — the react-freeze pattern that react-native-screens uses for
freezeOnBlur— React callscomponentWillUnmountand thencomponentDidMounton the same instance. If a batch timer was pending at the hide, the revived list can no longer schedule low-priority updates. When the list also had no items at the hide,cellsAroundViewportis{first: 0, last: -1}, so the high-priority path (last >= 0) cannot recover either and the render window stays atinitialNumToRenderregardless of how much data arrives afterwards.Field impact: a POS handheld app (react-native-screens with
freezeOnBlur) showed 12 of 28 order lines on a screen that was blurred while its list was still empty, and scrolling never rendered the rest.The fix is one line: reset the timer id to
nullright afterclearTimeoutincomponentWillUnmount.Changelog:
[General] [Fixed] - VirtualizedList: clear the pending batch-update timer id in componentWillUnmount so a list hidden and revived by Suspense (react-freeze / freezeOnBlur) resumes rendering new cells
Test Plan:
Added a regression test to
packages/virtualized-lists/Lists/__tests__/VirtualizedList-test.js:renders all cells after being hidden and revealed by Suspense with a pending batch update. It renders aVirtualizedListwithdata={[]}andinitialNumToRender={12}under a Suspense boundary on a concurrent root, simulates layout so a low-priority batch timer is pending, hides the subtree by suspending (never-resolving thenable, as react-freeze does), reveals it, updates to 28 items, simulates content layout and scroll, advances fake timers through several batching periods, and asserts that all 28 cells render.Expected length: 28,Received length: 12(the window never leaves the initial region).Verified against the published
@react-native/virtualized-lists0.85.3 (same code paths) as well: 12/28 before, 28/28 after.prettier --checkpasses on both touched files.