来源:2026-09-28 性能复审(基于 master@b2ac639)。单项影响都不大,归并记录。
A. AdBlock 页面渲染模式(#196 /#213 系列新增)
巨石组件宽订阅 src/pages/AdBlock.tsx:53-81:单组件订阅约 10 个 atom,isAdBlockLoadingAtom 在每个 mutation 首尾各翻一次 → 每次点击整页(源卡、whitelist、stats)至少重渲染 2 次。源卡、whitelist、StatCounter 均未抽 memo 子组件。
whitelist 全量渲染 AdBlock.tsx:760-772:全部条目渲染成 span+button,无虚拟化无 memo;[Enhancement] 白名单批量增删 + 多行输入 UI(同时修正 remove 校验) #196 bulk paste 可一次加数百条。且每个 mutation atom 成功后整表 getAdBlockState 重拉,每次点击 ≥2 次整份 whitelist IPC 往返。
per_source 线性查找 AdBlock.tsx:470-473:sources.map 内对 overlapReport.per_source.find,O(源数 × 报告行数) 每渲染。预建 Map 即可。
B. #90 已知未修残留
P-F7 src/pages/ProfileEdit.tsx:35,48-54:effect 依赖 derived profile 对象,每次 profiles 整表 refetch(tray profiles-updated 事件、apply/rollback 成功后)产生新 ref → draft 被重置,用户未保存的 name/description 编辑可能丢失 。这条偏正确性,建议优先于本组其他项。修:effect 仅依赖 [profileId],内部用 ref 取最新值。
P-F14 残留 ManagementDrawer.tsx:75-84:Escape listener 依赖 [open, onClose],而 onClose 是 Layout.tsx:205 的 inline 箭头 → drawer 打开期间 Layout 每次重渲染都 remove/add document listener。SystemHosts.tsx:194-217 有重复实现可一并收拾。
P-F5 残留 stores/profiles/actions.ts:302-313:fetchSnapshotsAtom 整表覆盖不做 cap(save 路径已有 MAX_SNAPSHOTS=50)。
P-F6 死代码 src/components/ApplyStatus.tsx:全仓无 import,未挂载([perf+security] Rust 后端 + TS 前端 + DNS 路径系统 review 发现汇总 (2026-07) #90 P-F6 指的问题已不存在于运行时),建议直接删除。
DiffView 展开无上限 src/components/DiffView.tsx:57-64:展开 unchanged 区域时全量渲染所有未变行,大 profile diff 可达数万 DOM 节点。加渲染上限或虚拟化。
A. AdBlock 页面渲染模式(#196/#213 系列新增)
src/pages/AdBlock.tsx:53-81:单组件订阅约 10 个 atom,isAdBlockLoadingAtom在每个 mutation 首尾各翻一次 → 每次点击整页(源卡、whitelist、stats)至少重渲染 2 次。源卡、whitelist、StatCounter均未抽 memo 子组件。AdBlock.tsx:760-772:全部条目渲染成 span+button,无虚拟化无 memo;[Enhancement] 白名单批量增删 + 多行输入 UI(同时修正 remove 校验) #196 bulk paste 可一次加数百条。且每个 mutation atom 成功后整表getAdBlockState重拉,每次点击 ≥2 次整份 whitelist IPC 往返。AdBlock.tsx:470-473:sources.map内对overlapReport.per_source.find,O(源数 × 报告行数) 每渲染。预建 Map 即可。B. #90 已知未修残留
src/pages/ProfileEdit.tsx:35,48-54:effect 依赖 derived profile 对象,每次 profiles 整表 refetch(trayprofiles-updated事件、apply/rollback 成功后)产生新 ref → draft 被重置,用户未保存的 name/description 编辑可能丢失。这条偏正确性,建议优先于本组其他项。修:effect 仅依赖[profileId],内部用 ref 取最新值。ManagementDrawer.tsx:75-84:Escape listener 依赖[open, onClose],而 onClose 是Layout.tsx:205的 inline 箭头 → drawer 打开期间 Layout 每次重渲染都 remove/add document listener。SystemHosts.tsx:194-217有重复实现可一并收拾。stores/profiles/actions.ts:302-313:fetchSnapshotsAtom整表覆盖不做 cap(save 路径已有MAX_SNAPSHOTS=50)。src/components/ApplyStatus.tsx:全仓无 import,未挂载([perf+security] Rust 后端 + TS 前端 + DNS 路径系统 review 发现汇总 (2026-07) #90 P-F6 指的问题已不存在于运行时),建议直接删除。src/components/DiffView.tsx:57-64:展开 unchanged 区域时全量渲染所有未变行,大 profile diff 可达数万 DOM 节点。加渲染上限或虚拟化。