[WEB] Round FlashList container measurements to device pixel on web#91799
Conversation
|
|
|
@codex review |
|
Codex Review: Didn't find any major issues. 🚀 ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
@ZhenjaHorbach Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppNA Android: mWeb Chrome2026-05-27.19.04.33.moviOS: HybridAppNA iOS: mWeb SafariIMG_2347.MP4MacOS: Chrome / Safari2026-05-27.18.57.04.mov |
|
🚧 @mountiny has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
Explanation of Change
Root cause
@shopify/flash-listexposes aroundOffPixel(value)helper that's meant to snap measured dimensions to the device-pixel grid. The native implementation does this viaPixelRatio.roundToNearestPixel, but the web implementation (measureLayout.web.ts) was a no-op (return value).That meant
measureFirstChildLayoutreturned the raw subpixelwidthfromgetBoundingClientRect(). That value flows intoViewHolderCollection.fixedContainerSize, which is the dep of auseLayoutEffectthat callsrecyclerViewContext.layout()→setLayoutTreeId→ re-render. Browser layout produces sub-pixel drift between measurements, the dep check treated them as different on every commit, and the effect re-armed itself indefinitely until React's update-depth guard fired.Fixed Issues
$ #91584
PROPOSAL: N/A
Tests
Offline tests
Same as in the Tests section.
QA Steps
// TODO: These must be filled out, or the issue title must include "[No QA]."
Same as in the Tests section.
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: mWeb Chrome
web_android.mp4
iOS: mWeb Safari
web_ios1.mov
web_ios.mov
MacOS: Chrome / Safari
web.mp4