[v1.3] 修正React重绘问题 (ScriptCard & ScriptTable) #1182
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.
問題見 #1180 (comment)
hooks 和 index 的部份是 AI 重新合并再分开而成 (重构整体)
ScriptCard 和 ScriptTable 主要是人工修改+AI 评价 (重构 Draggable 相关)
主要针对 ScriptCard 修改。相关修改也放到 ScriptTable 了
问题概述(背景与动机)
在脚本列表页面(ScriptList)的实际使用中,存在较为明显的性能瓶颈,尤其在脚本数量较多(50+)的场景下,主要表现为:
根因分析
经分析,问题主要由以下几方面共同导致:
dnd-kit 的 Context 级联更新问题
SortableContext 对
items的变化高度敏感。当scriptList的数组引用发生变化(即使内容变化极小)时,SortableContext 会生成新的items数组,并触发所有使用useSortable的子组件重新计算位置。由于 Context 更新不受
React.memo控制,最终导致整个列表被强制重渲染。函数引用不稳定导致 memo 失效
父组件向子组件传递的回调函数(如
handleRunStop等)依赖于t或其他频繁变化的依赖项,导致每次渲染都会生成新的函数引用。在 props 对比阶段,
React.memo判定引用变化,从而触发不必要的组件重渲染。状态更新缺乏精细化 diff 判断
hooks 中的
updateScripts等逻辑在更新状态时未区分“真实变化”和“无效更新”,即使仅修改单个脚本的局部字段(如runStatus),也会创建新的列表对象并触发全量setState和 render。其他影响 diff 效率的细节问题
上述问题叠加,最终导致列表在高数据量场景下出现明显的性能劣化。
解决方案与关键改动说明
本次优化围绕 “稳定引用、减少 Context 级联影响、提升 diff 精度” 三个核心方向,对相关组件和 hooks 进行了重构。所有改动均为性能优化,不涉及功能行为变更。
1. ScriptCard.tsx(卡片视图优化)
改动原因
旧实现中,
sortableIds每次渲染都会通过map生成对象数组,增加了 dnd-kit 内部对比成本,并放大了 Context 更新的影响范围。具体改动
useMemo缓存sortableIds,仅生成纯字符串 ID 数组(如['uuid1', 'uuid2']),避免传递对象引用。dnd-kit 对字符串数组的比较效率更高,可显著减少无效更新。
useCallback包裹handleDragEnd,并精简依赖项,仅依赖scriptListSortOrder,保证函数引用稳定。ScriptCardItem的React.memo比较逻辑,仅比较影响 UI 渲染的关键字段(如name、status、runStatus),忽略对视觉无影响的属性变化。- 列表 key 统一使用item.uuid作为稳定唯一标识,避免使用数组索引导致 DOM 重建。效果
拖拽及常规操作时,仅相关节点发生更新;在移除 dnd-kit 的场景下,
React.memo可完全生效(当前仍保留拖拽能力)。2. ScriptTable.tsx(表格视图优化)
改动原因
表格视图与卡片视图存在相同的问题:行组件依赖不稳定,在排序或操作单行时触发表格整体重渲染。
具体改动
useMemo缓存排序结果和渲染数据,避免重复计算。onClick、onToggle)统一使用useCallback,确保引用稳定。items仅传递 ID 数组~ - 使用
rectSortingStrategy,减少布局计算开销~uuid。效果
在大数据量表格中,对单行的操作不再触发整表重渲染。
3. hooks.tsx(状态管理与逻辑重构)
改动原因
原 hooks 实现缺乏变化判断和引用稳定机制,导致轻微状态更新被放大为全量更新,并沿组件树向下传播。
核心优化点
新增精细化 diff 判断,仅在新旧值不一致时才更新状态,避免无意义的新对象创建和
setState。在更新前先比较状态是否发生真实变化,防止无效 render。
handleDelete、handleConfig、handleRunStop、scriptListSortOrder等全部使用useCallback,并移除不必要的依赖(如稳定的t)。filterFuncs、统计数据等通过useMemo精准依赖,减少重复计算map + filter(Boolean)重建排序列表,逻辑更清晰all项使用真实数量而非脚本总数整体收益
hooks 逻辑更加模块化、可读性更强,类型安全性提升,同时显著减少无效渲染(80%+)。
4. 其他非核心优化
types/main.d.ts:细化类型定义,增强 TypeScript 严格性。性能收益与测试建议
性能收益
建议测试项
可通过
console.log("Rendered")验证是否存在全量重渲染