fix: optimize ArtifactListImpl
This commit is contained in:
@@ -1,8 +1,13 @@
|
||||
import { memo } from "react";
|
||||
|
||||
import { type ScheduleArtifact } from "../../services/api";
|
||||
import Icon from "../../components/common/Icon";
|
||||
import { shortHash } from "./utils";
|
||||
|
||||
export function ArtifactList({
|
||||
// 包裹 memo 让父级 SchedulePage 在画布交互(setSelectedNodeId /
|
||||
// setSelectedEdgeId / linkSourceId 等)重渲染时,artifact 卡片不会跟着
|
||||
// 重建/重绑拖拽事件 —— 减少拖动过程中的事件重绑与列表抖动。
|
||||
function ArtifactListImpl({
|
||||
artifacts,
|
||||
keyword,
|
||||
onDrop,
|
||||
@@ -77,3 +82,5 @@ export function ArtifactList({
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export const ArtifactList = memo(ArtifactListImpl);
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
type FormEvent,
|
||||
memo,
|
||||
type MouseEvent as ReactMouseEvent,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
@@ -307,6 +308,35 @@ export default function SchedulePage({
|
||||
: artifacts;
|
||||
}, [artifacts, artifactKeyword]);
|
||||
|
||||
// 稳定传给 ArtifactList 的 3 个回调,让 memo 真正生效 —— 否则父级
|
||||
// (SchedulePage) 任何 store 字段变化都会让卡片列表重新绑定拖拽事件,
|
||||
// 在拖动/快速 hover 时放大体感卡顿。
|
||||
const handleArtifactDrop = useCallback(
|
||||
(artifact: ScheduleArtifact, x: number, y: number) => {
|
||||
useSchedulesStore.getState().addArtifactAt(artifact, x, y);
|
||||
},
|
||||
[],
|
||||
);
|
||||
const handleArtifactDoubleClick = useCallback(
|
||||
(artifact: ScheduleArtifact) => {
|
||||
useSchedulesStore.getState().addArtifactAt(
|
||||
artifact,
|
||||
90 + (schedule?.nodes.length ?? 0) * 245,
|
||||
130,
|
||||
);
|
||||
},
|
||||
[schedule],
|
||||
);
|
||||
const handleArtifactContextMenu = useCallback(
|
||||
(event: ReactMouseEvent, artifact: ScheduleArtifact) => {
|
||||
openScheduleContextMenu(
|
||||
event as ReactMouseEvent<HTMLElement | SVGElement>,
|
||||
{ kind: "artifact", artifact },
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<section className="schedule-page">
|
||||
<header className="schedule-toolbar">
|
||||
@@ -364,9 +394,9 @@ export default function SchedulePage({
|
||||
<ArtifactList
|
||||
artifacts={filteredArtifacts}
|
||||
keyword={artifactKeyword}
|
||||
onDrop={(artifact, x, y) => void useSchedulesStore.getState().addArtifactAt(artifact, x, y)}
|
||||
onDoubleClick={(artifact) => void useSchedulesStore.getState().addArtifactAt(artifact, 90 + (schedule?.nodes.length ?? 0) * 245, 130)}
|
||||
onContextMenu={(event, artifact) => openScheduleContextMenu(event as ReactMouseEvent<HTMLElement | SVGElement>, { kind: "artifact", artifact })}
|
||||
onDrop={handleArtifactDrop}
|
||||
onDoubleClick={handleArtifactDoubleClick}
|
||||
onContextMenu={handleArtifactContextMenu}
|
||||
onKeywordChange={setArtifactKeyword}
|
||||
/>
|
||||
</aside>
|
||||
|
||||
@@ -294,10 +294,10 @@
|
||||
background: #fff;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
transition:
|
||||
transform .15s ease,
|
||||
box-shadow .15s ease,
|
||||
border-color .15s ease;
|
||||
/* hover 效果(border / box-shadow / transform)全部走合成层友好的属性,
|
||||
但禁止 transition:box-shadow 是 paint 操作,在 20+ 张卡片上快速
|
||||
划过鼠标会触发频繁重绘,导致悬浮卡顿;拖动时也会让 drag image 变重、
|
||||
视觉上"粘"在半动画上。直接瞬变,干净利落。 */
|
||||
}
|
||||
|
||||
.artifact-card:hover {
|
||||
|
||||
Reference in New Issue
Block a user