-
Notifications
You must be signed in to change notification settings - Fork 481
perf: improve Home first screen without perf marks #9527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf: improve Home first screen without perf marks #9527
Conversation
- Defer non-critical heavy work until UI idle (compat networks, autoSelect, approvals red-dot) - Speed up first All-Network requests; keep later debounce - Defer TokenManagement and Earn fetches from Home first screen - Add safe caching/forceRefresh for enabled-network compat calc
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds UI-idle deferment and debounce flows to delay expensive compatibility, approval, token, and earn fetches. Introduces deferHeavyWorkUntilUIIdle, guards and cancellation around listeners and initial fetches, feature gates to skip token/earn work, and a deferMs path for all-network compatibility resolution. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant UI as UI Component
participant Defer as deferHeavyWorkUntilUIIdle
participant Frames as RAF Loop
participant Interact as InteractionManager
participant Worker as Heavy Work (compat/approvals/tokens)
Note over UI,Defer: Idle-deferral flow added for expensive tasks
User->>UI: Mount or trigger feature (All Networks / Home)
UI->>Defer: call deferHeavyWorkUntilUIIdle(minFrames, includeInteractions)
Defer->>Frames: wait minFrames (requestAnimationFrame)
Frames-->>Defer: frames elapsed
alt includeInteractions == true
Defer->>Interact: wait for interactions/layout
Interact-->>Defer: interactions complete
end
Defer->>Frames: wait final frame
Frames-->>Defer: ready
Defer-->>UI: resolve (defer complete)
UI->>Worker: run heavy task (compat/approvals/tokens) with cancellation guard
Worker-->>UI: results (UI verifies not cancelled before setState)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (13)
packages/kit/src/components/AccountSelector/AllNetworksManagerTrigger.tsxpackages/kit/src/components/AccountSelector/hooks/useAutoSelectAccount.tsxpackages/kit/src/components/TokenListView/index.tsxpackages/kit/src/hooks/useAllNetwork.tspackages/kit/src/utils/deferHeavyWork.tspackages/kit/src/views/AssetList/hooks/useTokenManagement.tspackages/kit/src/views/Earn/EarnHome.tsxpackages/kit/src/views/Earn/components/Recommended.tsxpackages/kit/src/views/Earn/hooks/useEarnPortfolio.tspackages/kit/src/views/Home/components/EarnListView/EarnListView.tsxpackages/kit/src/views/Home/components/TokenListBlock/TokenListBlock.tsxpackages/kit/src/views/Home/pages/HomePageView.tsxpackages/kit/src/views/Home/pages/TokenListContainer.tsx
🧰 Additional context used
🧬 Code graph analysis (5)
packages/kit/src/components/TokenListView/index.tsx (1)
packages/kit/src/views/AssetList/hooks/useTokenManagement.ts (1)
useTokenManagement(23-249)
packages/kit/src/utils/deferHeavyWork.ts (2)
packages/shared/src/polyfills/polyfillsPlatform.js (1)
platformEnv(19-19)apps/desktop/app/libs/react-native-mock.ts (1)
InteractionManager(9-9)
packages/kit/src/views/Home/components/TokenListBlock/TokenListBlock.tsx (1)
packages/kit-bg/src/providers/ProviderApiAptos.ts (1)
network(200-202)
packages/kit/src/views/Home/pages/HomePageView.tsx (1)
packages/kit/src/utils/deferHeavyWork.ts (1)
deferHeavyWorkUntilUIIdle(47-61)
packages/kit/src/components/AccountSelector/hooks/useAutoSelectAccount.tsx (1)
packages/kit/src/utils/deferHeavyWork.ts (1)
deferHeavyWorkUntilUIIdle(47-61)
🔇 Additional comments (30)
packages/kit/src/components/TokenListView/index.tsx (3)
117-118: LGTM! New prop follows consistent patterns.The
deferTokenManagementprop is threaded correctly through the component interface and destructuring.Also applies to: 158-159
252-266: Confirm customTokens dependency is intentional.Adding
customTokensto the dependencies at line 265 is correct since it's used in thehideZeroBalanceTokensfilter (lines 232-240). However, verify this doesn't cause unintended re-renders whencustomTokensupdates frequently.
181-188: Add error recovery for token list initialization.The gating logic
!deferTokenManagement || tokenListState.initializedwill never activate token management if token list initialization fails. When a non-CanceredError occurs during fetch, the exception is rethrown (line 449) and the component crashes instead of gracefully degrading. Even for CanceledError, there's no fallback to setinitialized: true. Consider catching errors and either settinginitialized: trueas a fallback after retries, or implementing a timeout to prevent indefinite waits on slow networks.packages/kit/src/views/Home/components/EarnListView/EarnListView.tsx (1)
20-28: LGTM! Disabling fetch on Home card makes sense.Passing
enableFetch={false}to the Recommended component on the Home card aligns with the performance goal by using cached data only. The Earn tab will still fetch when truly active.packages/kit/src/views/Home/components/TokenListBlock/TokenListBlock.tsx (1)
2009-2009: LGTM! Consistent deferral for All Networks.Deferring token management when
network?.isAllNetworksis true aligns with the performance strategy. The boolean coercion is safe.packages/kit/src/views/Home/pages/TokenListContainer.tsx (1)
1935-1983: LGTM! Consistent deferral pattern.Adding
deferTokenManagement={!!network?.isAllNetworks}matches the usage in TokenListBlock.tsx. This ensures consistent behavior across All Networks views.packages/kit/src/components/AccountSelector/hooks/useAutoSelectAccount.tsx (2)
35-50: Cancellation logic looks sound.The
cancelledflag prevents heavy work from executing if the component unmounts during the deferral. The cleanup function correctly setscancelled = true. The pattern is correct.
37-40: Confirm deferral doesn't block critical auto-select.Deferring
autoSelectNextAccounton the home scene improves first-screen performance. However, verify that this doesn't delay account selection too long, causing the user to see an empty or incorrect account state.packages/kit/src/views/Earn/hooks/useEarnPortfolio.ts (2)
536-536: LGTM! Early return when inactive is efficient.Returning early when
!isActiveprevents unnecessary fetch work. This aligns with the performance goal.
764-764: LGTM! Focus override respects active state.The
overrideIsFocused: (isFocused) => isFocused && isActiveensures polling only runs when the Earn tab is both focused and active. This is the correct logic.packages/kit/src/views/Earn/components/Recommended.tsx (3)
223-231: LGTM! Prop default preserves existing behavior.The
enableFetchprop defaults totrue, ensuring existing usage isn't broken. The destructuring is clean.
249-251: LGTM! Early return when fetch disabled is correct.Returning cached
recommendedTokenswhenenableFetchis false avoids unnecessary fetches while still showing cached data. This is the right approach.
277-277: LGTM! Focus override respects enableFetch.The
overrideIsFocused: (isFocused) => isFocused && enableFetchensures fetching only occurs when both focused and fetch is enabled. Correct logic.packages/kit/src/views/Earn/EarnHome.tsx (1)
66-66: Focus state initialization is correct and causes no delay.Initializing
isEarnTabFocusedtofalseprevents unnecessary data fetching for invisible tabs. When the Earn tab becomes active,useListenTabFocusStateupdates the focus state immediately, which triggers data fetching right away throughusePromiseResult. The current implementation has no artificial delays.packages/kit/src/views/Home/pages/HomePageView.tsx (3)
6-6: LGTM: Clean imports for deferred work pattern.The CanceledError import and deferHeavyWorkUntilUIIdle utility align with the PR's strategy to defer heavy work until UI idle.
Also applies to: 46-46
87-90: Good: Ref tracks approval state across renders.This ref correctly maintains the latest
hasRiskApprovalsvalue for the async fetch closure, avoiding stale-closure issues.
161-209: Verify: Red-dot reset may cause brief flicker.The eager reset at line 166 clears
hasRiskApprovalsimmediately on account/network switch, even if the new context also has risk approvals. This could cause a brief red-dot disappearance followed by reappearance.Consider keeping the previous state until the new fetch completes, or add a loading flag to distinguish "fetching" from "confirmed no risk."
Do you want the red-dot to briefly disappear during switches, or should it persist until the new fetch confirms absence of risk?
packages/kit/src/views/AssetList/hooks/useTokenManagement.ts (1)
27-27: LGTM: Clean feature-flag for heavy token loading.The
enabledparameter correctly gates the expensive token aggregation logic. Whenfalse, it short-circuits early (lines 44-50) and returns empty collections, avoiding heavy DB queries and API calls. The dependency array (line 201) includesenabledto re-run when toggled.Also applies to: 32-32, 44-50, 201-201
packages/kit/src/utils/deferHeavyWork.ts (2)
3-14: LGTM: Robust frame deferral with fallback.The
nextFrameimplementation correctly prefersrequestAnimationFrameand falls back tosetTimeout(0)when RAF is unavailable. The fallback ensures compatibility across environments.
24-45: Good: Platform-guarded dynamic import prevents bundle bloat.The platform check (line 25) and dynamic
require(line 31) correctly avoid importing React Native'sInteractionManageron web/extension. The try-catch (lines 28-44) gracefully handles environments where the module is unavailable.packages/kit/src/components/AccountSelector/AllNetworksManagerTrigger.tsx (3)
45-68: Good: Deferred compat query with cancellation guard.The
shouldEnableCompatQueryflag (lines 45-48) correctly identifies when deferment is needed (All Networks + non-Others wallet). The effect (lines 53-68) defers heavy work usingdeferHeavyWorkUntilUIIdleand updatesisDeferredReadywith proper cancellation handling via thecancelledflag.
70-75: Clever: Empty string gates expensive hook until UI idle.The
compatQueryWalletIdmemo returns an empty string untilisDeferredReadyis true. This effectively disables the expensiveuseEnabledNetworksCompatibleWithWalletIdInAllNetworkshook during initial render, deferring the heavy compat query.
89-119: Skeleton correctly displays during deferment.The refresh handlers (lines 89-99) properly skip when deferment is active. The hook returns an empty
compatibleNetworksarray whenwalletIdis empty (line 497-498 in useAllNetwork.ts), which triggers the skeleton condition at line 151 (enabledNetworksCompatibleWithWalletId.length === 0). The deferment flow is sound: whileisDeferredReadyis false,compatQueryWalletIdremains empty, the hook returns an empty array, and the skeleton displays as intended.packages/kit/src/hooks/useAllNetwork.ts (7)
30-43: LGTM: Type-safe result structure.The
IEnabledNetworksCompatResulttype andgetEmptyEnabledNetworksResulthelper provide a consistent structure for enabled networks data. This improves type safety and makes default initialization cleaner.
164-164: Good: Smart debouncing—immediate first run, debounced thereafter.The
runCountRefpattern (lines 164, 171, 214) tracks consecutive runs. First invocation (runCountRef === 0) skips the debounce (lines 185-195), ensuring fast initial paint. Subsequent runs waitPOLLING_DEBOUNCE_INTERVALto reduce thrashing. The ref resets on account/network/wallet changes (line 171), treating each context switch as a new "first run."Also applies to: 171-181, 185-195, 214-214
217-283: Excellent: Parallel execution of onStarted and account fetch.The refactor runs
onStarted(line 227) andgetAllNetworkAccounts(line 238) in parallel rather than sequentially. This reduces blocking time during the critical first-screen window. Error capture viaonStartedError(line 232) and deferred throw (line 281) ensures errors don't silently disappear while still allowing the accounts fetch to complete.
441-443: Critical: Finally block ensures isFetching cleanup.The
finallyblock (line 441-443) guarantees thatisFetching.currentresets even if errors occur. This prevents the hook from getting stuck in a "fetching" state that blocks subsequent runs.
484-484: Good: deferMs parameter enables controllable compat query delay.The new
deferMsparameter (lines 484, 491) allows callers to defer heavy compat network queries. Lines 518-520 wait for the specified duration after fetching enabled/disabled networks but before computing compatibility. This aligns with the PR's strategy to defer non-critical work until UI idle.Also applies to: 491-491, 518-520
464-464: Observe: Debounce disabled via debounced: 0.Line 464 sets
debounced: 0, disablingusePromiseResult's built-in debouncing. The custom debounce logic (lines 185-195) usingrunCountRefreplaces it. This is intentional and allows the first run to execute immediately.
285-330: Remove this comment—the early-exit concern is incorrect.
perf.done()at line 315 is just a performance marker, not a return statement. The code continues normally to line 337 where it executes the main requests block. The function doesn't exit early. Additionally,allNetworkDataInit.currentis properly reset tofalsein the useEffect (line 170) when dependencies change, so fresh data fetches do occur on subsequent calls.Likely an incorrect or invalid review comment.
…ub.com/littlesmilelove/app-monorepo into xeon/performance-fix-home-first-screen
|
@coderabbitai resolve |
✅ Actions performedComments resolved. |
|
@codex review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/kit/src/views/Home/pages/HomePageView.tsx (1)
190-238: Solid deferred approval fetching pattern.The cancellation logic is correct. The flow properly resets stale state, defers heavy work, then guards against races with
cancelledchecks.One minor note: the catch block re-throws without logging. This was flagged in a past review.
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (2)
packages/kit/src/utils/deferHeavyWork.tspackages/kit/src/views/Home/pages/HomePageView.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
packages/kit/src/views/Home/pages/HomePageView.tsx (1)
packages/kit/src/utils/deferHeavyWork.ts (1)
deferHeavyWorkUntilUIIdle(35-49)
packages/kit/src/utils/deferHeavyWork.ts (1)
packages/shared/src/polyfills/polyfillsPlatform.js (1)
platformEnv(19-19)
🔇 Additional comments (5)
packages/kit/src/views/Home/pages/HomePageView.tsx (2)
5-6: LGTM!Imports are clean and used appropriately in the new deferred approval logic.
Also applies to: 45-45
116-119: LGTM!Good use of a ref to track state without re-triggering the effect. This avoids stale closures.
packages/kit/src/utils/deferHeavyWork.ts (3)
1-2: LGTM!Clean imports. Both are used appropriately.
4-26: LGTM!The RAF-with-fallback pattern is solid.
Math.max(0, frames)guards against negative counts. Simple and effective.
35-49: LGTM!The sequencing is clear: wait for frames, optionally wait for interaction settling, then one more frame for layout flush. Callers handle cancellation via their own flags. This works well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ub.com/littlesmilelove/app-monorepo into xeon/performance-fix-home-first-screen
Head branch was pushed to by a user without write access
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/kit/src/hooks/useAllNetwork.ts (1)
207-207: Remove debug console.log before merging.This debug statement will clutter production logs. Remove or wrap in a debug/development check.
🔎 Proposed fix
- console.log('useAllNetworkRequests >>>>>>>>>>>>>>'); + // console.log('useAllNetworkRequests >>>>>>>>>>>>>>');Or better, remove entirely if not needed for debugging.
♻️ Duplicate comments (1)
packages/kit/src/hooks/useAllNetwork.ts (1)
341-404: Add clarifying comments for these branching paths.These two paths (cache warm vs. cache cold) handle different scenarios. Brief inline comments would help future readers understand:
- Line 341: Cache is warm → parallel fetch all networks
- Line 364: Cache is cold → fetch indexed backends first, then non-indexed
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/kit/src/hooks/useAllNetwork.ts
🧰 Additional context used
🧬 Code graph analysis (1)
packages/kit/src/hooks/useAllNetwork.ts (5)
packages/kit-bg/src/vaults/types.ts (1)
IAccountDeriveTypes(136-140)packages/shared/types/index.ts (1)
IServerNetwork(49-71)packages/shared/src/consts/walletConsts.ts (1)
POLLING_DEBOUNCE_INTERVAL(10-10)packages/kit-bg/src/services/ServiceAllNetwork/ServiceAllNetwork.ts (1)
IAllNetworkAccountInfo(29-41)packages/shared/src/utils/promiseUtils.ts (1)
promiseAllSettledEnhanced(141-153)
🔇 Additional comments (7)
packages/kit/src/hooks/useAllNetwork.ts (7)
30-43: Clean extraction of result type and factory function.Good move. The
getEmptyEnabledNetworksResultfactory ensures fresh objects each call. This avoids shared-reference bugs.
164-181: Solid approach for first-run bypass of debounce.Resetting
runCountRefon context changes ensures the first fetch is immediate. Subsequent fetches wait forPOLLING_DEBOUNCE_INTERVAL. The expanded dependency array is correct.
217-234: Good parallel execution, but check failure semantics.Running
onStartedandgetAllNetworkAccountsin parallel is a smart optimization. The error capture + re-throw pattern works.One concern: if
onStartedfails,clearAllNetworkData(line 219) has already run. The user sees cleared data until the next successful fetch. Confirm this is acceptable UX.
468-471: Correct: disable built-in debounce for manual control.Setting
debounced: 0and handling it manually (lines 193-195) allows the first request to be immediate. Good alignment with the PR goals.
522-524: Deferral placed after initial fetches, before heavy processing.The
deferMswait happens after network state is fetched but before the heavy compatibility processing. This is a sensible split - UI can paint while expensive work waits.
497-510: Stable initial result with correct early-exit handling.The memoized
initResultprovides a stable reference for the initial state. Early returns create fresh empty objects, which is fine since those paths indicate invalid inputs.
185-195: Debounce logic is safe from state-update leaks but waits aren't cancellable.
timerUtils.wait()can't be cancelled if the component unmounts mid-wait. However,usePromiseResultprevents state updates after unmount through itsisEffectValidflag andshouldSetState()checks (which verifyisMountedRef). This prevents memory leaks, though the promise itself still resolves. If you want to optimize further, consider usingAbortControllerfor the timer to avoid unnecessary promise completions after unmount.
Home 首屏性能优化
TL;DR
进入 Home(尤其是
All‑Networks)时,首屏“Loading 迟到/卡顿”的根因不是单点,而是首屏窗口内并发触发了多条重链路(All‑Network 账户构建、兼容网络解析、autoSelect 级联刷新、TokenManagement、Earn 推荐拉取、Approvals 风险检测等),导致主线程/桥接被占用,UI 不能及时 paint。这个 PR 的核心策略是:不改业务结果,只改执行时机与并发结构,把“首屏不必需”的重工作稳定后置到 UI 空闲后执行,并减少首屏阶段的重复计算与无效等待。
背景与目标
现象(用户可感知)
在进入 Home(All‑Networks 场景)后常见:
Home:mount -> Home:loading:show之间出现“卡住”的空窗。Home:done:tokens仍可能被尾部网络/计算拖长(本 PR 不以消除长尾为目标)。目标(本 PR 要保证的事情)
非目标(本 PR 不做什么)
策略总览(为什么这样做不会影响正确性)
用“UI 空闲边界”替代固定毫秒延时
setTimeout(1200/2000ms)在不同设备/负载下不稳定,且容易带来偶发状态竞态。requestAnimationFrame)+(native)等交互完成(InteractionManager.runAfterInteractions)+ 再等待一帧,确保首屏 paint 优先。把“非首屏必需”的入口链路后置
减少重复计算/无效等待,同时保留后续稳定性
改动明细(按主题解释每个改动)
A) 统一的“UI 空闲后执行”工具
packages/kit/src/utils/deferHeavyWork.tsdeferHeavyWorkUntilUIIdle({ minFrames, includeInteractions })requestAnimationFrame(无 raf 则setTimeout(0))InteractionManager.runAfterInteractionsB) All‑Networks 兼容网络解析后置(减少首屏同步重算)
packages/kit/src/components/AccountSelector/AllNetworksManagerTrigger.tsxuseEnabledNetworksCompatibleWithWalletIdInAllNetworks的重计算:walletId先置空(不跑 compat)walletId触发计算C) Home 场景延后 autoSelect(减少首屏级联刷新)
packages/kit/src/components/AccountSelector/hooks/useAutoSelectAccount.tsxsceneName === home时:先deferHeavyWorkUntilUIIdle()再触发autoSelectNextAccountD)
useAllNetworkRequests:首轮加速 + 后续保持稳定(同时修复并发与等待细节)packages/kit/src/hooks/useAllNetwork.tsD1. 首轮取消 debounce、后续轮次保留节流
usePromiseResult的debounced设为0runCountRef控制:仅第二轮及以后才wait(POLLING_DEBOUNCE_INTERVAL)wait()只在“确认本轮会真正发起 All‑Networks 请求”时才执行(避免 disabled/缺参/正在 fetching 时白等)D2.
onStarted与getAllNetworkAccounts并行化(并避免 Promise 未处理异常)onStarted()提前启动为 task,与getAllNetworkAccounts并行onStarted过早 reject 触发unhandledRejection,创建 task 时先.catch(),随后在 await 后按原语义抛出isFetching.current改为try/finally复位,避免异常路径下卡死onStarted仍会被等待完成(不会提前进入后续步骤);失败仍会按原语义抛出,只是更安全地处理时序。F) TokenManagement:All‑Networks 首屏延后启用(避免重查询抢首屏资源)
packages/kit/src/components/TokenListView/index.tsxpackages/kit/src/views/AssetList/hooks/useTokenManagement.tspackages/kit/src/views/Home/pages/TokenListContainer.tsxpackages/kit/src/views/Home/components/TokenListBlock/TokenListBlock.tsxTokenListView新增deferTokenManagement?: booleanuseTokenManagement新增enabled?: boolean:disabled 时直接返回空结果,不触发 All‑Network 账户构建/本地聚合deferTokenManagement={true},并以tokenListState.initialized作为启用时机getAllNetworkAccounts等重链路,首屏阶段会与 token refresh/账户构建抢资源。G) Earn:Home 首屏只读缓存,不触发重 fetch
packages/kit/src/views/Earn/components/Recommended.tsxpackages/kit/src/views/Home/components/EarnListView/EarnListView.tsxpackages/kit/src/views/Earn/EarnHome.tsxpackages/kit/src/views/Earn/hooks/useEarnPortfolio.tsRecommended新增enableFetch?: boolean,enableFetch=false时不触发 fetch(并通过overrideIsFocused绑定可见性)<Recommended enableFetch={false} />isEarnTabFocused初始false,并用isActiveguard 限制 portfolio 刷新仅在 Earn 真正 active 时执行H) Approvals:不阻塞首屏,但保证红点状态不 stale
packages/kit/src/views/Home/pages/HomePageView.tsxfetchAccountApprovals来更新hasRiskApprovals(红点)deferHeavyWorkUntilUIIdle()再 fetch,避免与首屏 token 刷新/All‑Network 构建抢资源效果(来自带监控验证分支的趋势)
不同设备/冷启动状态会波动,但趋势稳定:
Home:mount -> Home:loading:show:明显提前(常见 1–2s 量级改善)jsblock:main明显减少(Loading 迟到问题基本消失)Home:tokens:allnet:deps:ready -> run:从“秒级等待”降到“接近 0”Home:done:tokens)回归关注点 / QA Checklist
tokenListState.initialized后恢复一致。Summary by CodeRabbit
Performance Improvements
New Features
✏️ Tip: You can customize this high-level summary in your review settings.