fix: keep Tabs scroll extent in sync after tab switches and async refreshes (OK-57257 OK-57977)#12530
Open
huhuanming wants to merge 1 commit into
Open
fix: keep Tabs scroll extent in sync after tab switches and async refreshes (OK-57257 OK-57977)#12530huhuanming wants to merge 1 commit into
huhuanming wants to merge 1 commit into
Conversation
huhuanming
force-pushed
the
codex/fix-defi-scroll-extent
branch
from
July 17, 2026 03:29
aef493d to
10223a7
Compare
huhuanming
marked this pull request as ready for review
July 17, 2026 06:09
huhuanming
requested review from
ezailWang,
originalix,
revan-zhang and
sidmorizon
as code owners
July 17, 2026 06:09
huhuanming
enabled auto-merge (squash)
July 17, 2026 06:18
huhuanming
force-pushed
the
codex/fix-defi-scroll-extent
branch
from
July 17, 2026 06:56
232f949 to
84c4b39
Compare
huhuanming
force-pushed
the
codex/fix-defi-scroll-extent
branch
from
July 17, 2026 07:00
84c4b39 to
ab8ee16
Compare
huhuanming
force-pushed
the
codex/fix-defi-scroll-extent
branch
from
July 17, 2026 12:55
ab8ee16 to
c477277
Compare
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
OK-57257 OK-57977
Summary
Tabs.ContainerTabs.ScrollViewTabs.Listpages on their existing explicit-height contractReported problems
OK-57257 — DeFi cannot reach the bottom after switching tabs
The issue video starts on a tall DeFi page, switches to the shorter NFT tab, and then returns to DeFi. Wheel scrolling stops at an older, shorter extent, leaving the lower protocol sections and Support Hub cards unreachable.
The layout transition is tall -> short -> tall. Restoring the DeFi scene can increase its live
scrollHeightwithout rebuilding the shared horizontal Tabs list at the same height.OK-57977 — the active DeFi page cannot reach the bottom after an account/network change
The Jira video shows the same symptom without requiring a tab change:
This is a different trigger from OK-57257, but the same shared layout failure: the focused tab receives taller async content while the outer Tabs list retains an earlier height.
QA retest — relaunch while DeFi is active
QA reported an additional stable path after testing the first version of this PR:
The attached logs show the Home UI initializing first, followed several seconds later by the supported-protocol and position responses under the configured slow-4G profile. This makes the first DeFi measurement an initial/skeleton measurement; later data changes the DOM while DeFi remains focused.
Why the first shared fix was still incomplete
The first revision correctly moved the workaround out of
DeFiContainerand made the registeredTabs.ScrollViewroot the live measurement source. It also attachedResizeObserverto the root and its direct content nodes.However, those direct nodes were captured only once when the observer was attached. On relaunch or another async refresh, React can add or replace content after that snapshot:
ResizeObservertargetTabs.ScrollViewborder box can remain pinned by its parent layoutscrollHeightchanges, which is not itself aResizeObservernotificationThis explains QA's sequence precisely: switching tabs after an update re-attached the observer and temporarily fixed the page; relaunching into a fresh async DeFi load recreated the stale snapshot.
Root cause and relationship between the issues
All three paths increase a focused tab's live content extent while the shared horizontal list still owns an older numeric height. The failure belongs to
Tabs.Container, not DeFi margin/padding and not a background-service scroll state.Fix
For registered
Tabs.ScrollViewpages,Tabs.Containernow combines two observers with separate responsibilities:ResizeObserverwatches the root and its current direct content nodes for intrinsic size changes such as image, font, and layout resolution.MutationObserverwatches structuralchildListchanges in the focused ScrollView subtree.scrollHeightand writes that live value to the shared horizontal list.The mutation observer intentionally excludes attribute/style observation, so updating the list height cannot feed back into the observer. The fix is generic to every flow-content tab using
Tabs.ScrollView; business pages do not need selectors, focus-specific timers, or height reports.The previous DeFi-specific registration is removed. In particular, it no longer caches a sampled DeFi height that can override later live DOM measurements.
Stable reproduction script
Run against the desktop client on CDP port 9222:
The scenario now validates three phases:
The CDP connection also waits for the OneKey renderer to finish booting, so the scenario can be started together with the app instead of racing the initial page load.
Before/after evidence
Before this revision
On the first shared-fix implementation, adding a
160 pxdirect child produced:5178 pxscrollHeight:5338 px5178 px160 pxThe new node was absent from the one-time
ResizeObservertarget snapshot.After this revision
With the deterministic
96 pxprobe:5178 -> 5274 px5043 -> 5139 px5139 / 51390 pxThe structural observer detects the insertion, refreshes the target set, and measures the live root extent.
App relaunch validation
Validation used the real release-based Electron client with desktop network throttling enabled (
slow4g,562.5 mslatency).After a full process exit and restart (
isSoftRestart: false), the scenario waited for DeFi's async content, then checked the bottom before any tab round trip:scrollTop = maxScrollTop = 50435178 / 5178 px0 px0 pxcoldStartClipped=falseThe subsequent DeFi -> NFT -> DeFi check and direct-node growth probe also passed. A separate full run repeated the tab round trip 8 times; all 8 were clean.
QA acceptance
Please recheck all three routes with wheel input:
Repeat long -> short -> long data transitions where possible. None of the routes should require a recovery tab switch.
Checks
release/v6.5.0at2ebdd41fddc4772776fe) and 4 changed filesnode --check scenarios/regression.mjsoxlint --deny-warnings: 0 warnings, 0 errorsoxlint --deny-warnings: 0 warnings, 0 errorstsgo -p ./tsconfig.json --noEmit: passedgit diff --check: passedREGRESSION PASSyarn agent:check --profile commitcannot spawn its child commands correctly on this Windows checkout (exitCode: nullin 0-3 ms).yarn lint:stagedalso relies on Unix-onlygrep/xargs. The corresponding oxlint, syntax, diff, and tsgo checks above were run directly and passed.