Skip to content

[v1.3] 修正React重绘问题 (Popup)#1181

Merged
CodFrm merged 11 commits intoscriptscat:release/v1.3from
cyfung1031:pr-973-02
Feb 8, 2026
Merged

[v1.3] 修正React重绘问题 (Popup)#1181
CodFrm merged 11 commits intoscriptscat:release/v1.3from
cyfung1031:pr-973-02

Conversation

@cyfung1031
Copy link
Collaborator

@cyfung1031 cyfung1031 commented Feb 1, 2026

垃圾React设计(State设计)导致额外的心力去解决那些烦人的UI重绘问题

#1180 (comment)

你只有20个脚本的话重绘问题是看不出来
但我有差不多100个的话,按钮一按什么的很容易就看出来:「肯定又是垃圾React的问题」

@cyfung1031 cyfung1031 changed the title 修正React重绘问题 (Popup) [v1.3] 修正React重绘问题 (Popup) Feb 1, 2026
@cyfung1031 cyfung1031 mentioned this pull request Feb 1, 2026
@cyfung1031 cyfung1031 added P0 🚑 需要紧急处理的内容 hotfix 需要尽快更新到扩展商店 UI/UX 页面操作/显示相关 labels Feb 1, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 旨在缓解 Popup 页面在脚本数量较多时的 React 额外重绘/卡顿问题,通过尽量复用 list/item 的引用与缓存异步 metadata 合并结果,减少不必要的组件更新。

Changes:

  • Popup/App.tsx 抽出 updateList,在子项无变化时复用原 list 引用,降低 setState 触发的重绘频率
  • ScriptMenuList 中引入 metadata 合并缓存(Map + WeakMap),尽量复用合并后的 item 引用,减少列表项的重复渲染
  • 调整 ScriptSettinguseMemo 依赖,避免仅因 script 对象引用变化导致配置项重算

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/pages/popup/App.tsx 新增 updateList,尝试在启用/删除/菜单更新时减少不必要的 list 引用变化与重绘
src/pages/components/ScriptSetting/index.tsx useMemo 依赖从 script 调整为 script.uuid,降低无关重算
src/pages/components/ScriptMenuList/index.tsx 重构 metadata 异步合并逻辑,引入模块级缓存与 WeakMap 复用 merged item 引用

Comment on lines +63 to +65
if (!changed && list.map((e) => e.uuid).join(",") !== newList.map((e) => e.uuid).join(",")) {
// 单一项未有改变,但因为 sort值改变 而改变了次序
changed = true;
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

list.map(...).join(",") !== newList.map(...).join(",") 这段在 !changed 时每次都会做两次 O(n) 的遍历/拼接,即使没有开启 sort 也会执行,可能抵消这里想减少重绘的优化效果。建议仅在 options?.sort 为 true(且确实需要判断排序变化)时再做该比较,或用更轻量的顺序比较方式。

Suggested change
if (!changed && list.map((e) => e.uuid).join(",") !== newList.map((e) => e.uuid).join(",")) {
// 单一项未有改变,但因为 sort值改变 而改变了次序
changed = true;
if (!changed && options?.sort) {
// 单一项未有改变,但因为 sort值改变 而改变了次序
if (list.length !== newList.length) {
changed = true;
} else {
for (let i = 0; i < list.length; i++) {
if (list[i].uuid !== newList[i].uuid) {
changed = true;
break;
}
}
}

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

@cyfung1031 cyfung1031 Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

太长了。这个 micro optimization 不值得
另外这个对比在 前跟后的sort值不一致 的情况都会起作用

Comment on lines +349 to +350
metadata = script?.metadata || {}; // 即使 scriptDAO 返回失败也 fallback 一个空物件
cacheMetadata.set(uuid, metadata);
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fetchMergedListscriptDAO.get(uuid) 读不到脚本时会把 metadata 回退成 {} 并写入 cacheMetadata,导致后续即使数据恢复也不会再尝试读取真实 metadata(缓存被“永久”填充)。建议只在成功读取到 script 时才写入缓存,或缓存 undefined 以允许后续重试/失效刷新。

Suggested change
metadata = script?.metadata || {}; // 即使 scriptDAO 返回失败也 fallback 一个空物件
cacheMetadata.set(uuid, metadata);
if (script) {
// 只有在成功读取到脚本时才写入缓存
metadata = script.metadata || {};
cacheMetadata.set(uuid, metadata);
} else {
// 读取失败时只在当前调用中使用空物件,不写入缓存,允许后续重试
metadata = {};
}

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

对。如果真的发生读取失败,就不要再尝试
不然这个物件参考会改不停

Comment on lines 48 to 68
const updateList = (list: ScriptMenu[], update: TUpdateEntryFn, options: TUpdateListOption | undefined) => {
// 如果更新跟当前 list 的子项无关,则不用更改 list 的物件参考
const newList = [];
let changed = false;
for (let i = 0; i < list.length; i++) {
const oldItem = list[i];
const newItem = update(oldItem); // 如没有更改,物件参考会保持一致
if (newItem !== oldItem) changed = true;
if (newItem) {
newList.push(newItem);
}
}
if (options?.sort) {
newList.sort(scriptListSorter);
}
if (!changed && list.map((e) => e.uuid).join(",") !== newList.map((e) => e.uuid).join(",")) {
// 单一项未有改变,但因为 sort值改变 而改变了次序
changed = true;
}
return changed ? newList : list; // 如子项没任何变化,则返回原list参考
};
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里新增了 updateList(决定是否复用旧 list 引用、以及排序/删除逻辑),属于影响渲染与状态更新的关键路径;当前 tests/pages/popup/App.test.tsx 只覆盖了基础渲染,未覆盖“无变更时必须保持引用不变 / sort 时顺序变化需触发更新”等场景。建议补充针对该更新策略的测试(可考虑抽到独立 util 后做纯函数单测),避免后续优化回归。

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

???

cyfung1031 and others added 2 commits February 7, 2026 17:41
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@CodFrm CodFrm merged commit d1161b7 into scriptscat:release/v1.3 Feb 8, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hotfix 需要尽快更新到扩展商店 P0 🚑 需要紧急处理的内容 UI/UX 页面操作/显示相关

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants