Skip to content

Conversation

@cyfung1031
Copy link
Collaborator

@cyfung1031 cyfung1031 commented Feb 1, 2026

問題見 #1180 (comment)

hooks 和 index 的部份是 AI 重新合并再分开而成 (重构整体)
ScriptCard 和 ScriptTable 主要是人工修改+AI 评价 (重构 Draggable 相关)
主要针对 ScriptCard 修改。相关修改也放到 ScriptTable 了


问题概述(背景与动机)

在脚本列表页面(ScriptList)的实际使用中,存在较为明显的性能瓶颈,尤其在脚本数量较多(50+)的场景下,主要表现为:

  • 列表频繁发生闪烁和卡顿。例如在拖拽排序、启用/停用脚本、运行/停止脚本等操作时,整个列表(所有 ScriptCardItem 或表格行)会被重新渲染。
  • CPU 占用率较高,显著影响选项页的整体交互体验。
  • 该问题在 React 与 dnd-kit 组合使用时较为常见,但若不进行针对性优化,会直接导致页面流畅度下降,影响用户体验。

根因分析

经分析,问题主要由以下几方面共同导致:

  1. dnd-kit 的 Context 级联更新问题
    SortableContext 对 items 的变化高度敏感。当 scriptList 的数组引用发生变化(即使内容变化极小)时,SortableContext 会生成新的 items 数组,并触发所有使用 useSortable 的子组件重新计算位置。
    由于 Context 更新不受 React.memo 控制,最终导致整个列表被强制重渲染。

  2. 函数引用不稳定导致 memo 失效
    父组件向子组件传递的回调函数(如 handleRunStop 等)依赖于 t 或其他频繁变化的依赖项,导致每次渲染都会生成新的函数引用。
    在 props 对比阶段,React.memo 判定引用变化,从而触发不必要的组件重渲染。

  3. 状态更新缺乏精细化 diff 判断
    hooks 中的 updateScripts 等逻辑在更新状态时未区分“真实变化”和“无效更新”,即使仅修改单个脚本的局部字段(如 runStatus),也会创建新的列表对象并触发全量 setState 和 render。

  4. 其他影响 diff 效率的细节问题

    • 使用数组索引作为 key,导致 React 在列表变动时无法复用节点。
    • useEffect / useMemo / useCallback 依赖控制不够严格,增加了不必要的重新计算。

上述问题叠加,最终导致列表在高数据量场景下出现明显的性能劣化。

解决方案与关键改动说明

本次优化围绕 “稳定引用、减少 Context 级联影响、提升 diff 精度” 三个核心方向,对相关组件和 hooks 进行了重构。所有改动均为性能优化,不涉及功能行为变更。

1. ScriptCard.tsx(卡片视图优化)

改动原因
旧实现中,sortableIds 每次渲染都会通过 map 生成对象数组,增加了 dnd-kit 内部对比成本,并放大了 Context 更新的影响范围。

具体改动

  • 使用 useMemo 缓存 sortableIds,仅生成纯字符串 ID 数组(如 ['uuid1', 'uuid2']),避免传递对象引用。
    dnd-kit 对字符串数组的比较效率更高,可显著减少无效更新。
  • 使用 useCallback 包裹 handleDragEnd,并精简依赖项,仅依赖 scriptListSortOrder,保证函数引用稳定。
  • 强化 ScriptCardItemReact.memo 比较逻辑,仅比较影响 UI 渲染的关键字段(如 namestatusrunStatus),忽略对视觉无影响的属性变化。
    - 列表 key 统一使用 item.uuid 作为稳定唯一标识,避免使用数组索引导致 DOM 重建。

效果
拖拽及常规操作时,仅相关节点发生更新;在移除 dnd-kit 的场景下,React.memo 可完全生效(当前仍保留拖拽能力)。

2. ScriptTable.tsx(表格视图优化)

改动原因
表格视图与卡片视图存在相同的问题:行组件依赖不稳定,在排序或操作单行时触发表格整体重渲染。

具体改动

  • 使用 useMemo 缓存排序结果和渲染数据,避免重复计算。
  • 所有事件处理函数(如 onClickonToggle)统一使用 useCallback,确保引用稳定。
  • 规范 dnd-kit 的使用方式:
    • items 仅传递 ID 数组
      ~ - 使用 rectSortingStrategy,减少布局计算开销~
  • 表格行 key 同样统一使用 uuid

效果
在大数据量表格中,对单行的操作不再触发整表重渲染。

3. hooks.tsx(状态管理与逻辑重构)

改动原因
原 hooks 实现缺乏变化判断和引用稳定机制,导致轻微状态更新被放大为全量更新,并沿组件树向下传播。

核心优化点

  • updateScripts
    新增精细化 diff 判断,仅在新旧值不一致时才更新状态,避免无意义的新对象创建和 setState
  • 消息监听逻辑(如 scriptRunStatus、enableScripts)
    在更新前先比较状态是否发生真实变化,防止无效 render。
  • 回调函数稳定化
    handleDeletehandleConfighandleRunStopscriptListSortOrder 等全部使用 useCallback,并移除不必要的依赖(如稳定的 t)。
  • 搜索与过滤逻辑优化
    • 使用 active 标志防止异步搜索竞态问题
    • filterFuncs、统计数据等通过 useMemo 精准依赖,减少重复计算
  • 其他调整
    • 使用 map + filter(Boolean) 重建排序列表,逻辑更清晰
    • 标签及来源统计修正,all 项使用真实数量而非脚本总数

整体收益
hooks 逻辑更加模块化、可读性更强,类型安全性提升,同时显著减少无效渲染(80%+)。

4. 其他非核心优化

  • Sidebar:微调渲染逻辑,减少父子组件间的更新传染。
  • types/main.d.ts:细化类型定义,增强 TypeScript 严格性。

性能收益与测试建议

性能收益

  • 列表操作过程流畅,闪烁和卡顿问题消失
  • 渲染次数下降
  • 在大规模脚本场景下,CPU 占用显著降低

建议测试项

  • 50+ 脚本场景下:拖拽排序、运行/停止、搜索操作
    可通过 console.log("Rendered") 验证是否存在全量重渲染
  • 使用 React DevTools Profiler 对比优化前后的渲染树
  • 功能回归:
    • 拖拽排序结果持久化
    • 排序与服务端同步
    • 搜索防抖逻辑

@cyfung1031 cyfung1031 added P0 🚑 需要紧急处理的内容 hotfix 需要尽快更新到扩展商店 UI/UX 页面操作/显示相关 labels Feb 1, 2026
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.

1 participant