feat(canvas): optimize CanvasAssetsTab and CanvasPromptsTab with memoization to improve performance

This commit is contained in:
HouYunFei
2026-07-18 08:27:20 +08:00
parent 75c22c2f9f
commit b5dc9c8a87
2 changed files with 6 additions and 5 deletions
+1
View File
@@ -3,6 +3,7 @@
## Unreleased ## Unreleased
+ [新增] 左侧画布面板新增「提示词库」Tab,按来源折叠分组。 + [新增] 左侧画布面板新增「提示词库」Tab,按来源折叠分组。
+ [修复] 处于「提示词库/资产」Tab 时拖动画布元素卡顿,面板内容不再随节点更新重渲染。
+ [新增] 提示词来源增加自定义脚本抓取功能、支持新增来源。 + [新增] 提示词来源增加自定义脚本抓取功能、支持新增来源。
## v0.9.0 - 2026-07-17 ## v0.9.0 - 2026-07-17
@@ -1,4 +1,4 @@
import { useMemo, useRef, useState, type PointerEvent as ReactPointerEvent } from "react"; import { memo, useMemo, useRef, useState, type PointerEvent as ReactPointerEvent } from "react";
import { App, Empty, Input, Popconfirm, Select, Spin, Tag } from "antd"; import { App, Empty, Input, Popconfirm, Select, Spin, Tag } from "antd";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { BookOpen, Check, ChevronRight, Download, Eye, FileText, Image as ImageIcon, ListChecks, Music2, Plus, Search, Settings2, Square, Trash2, Type, Video } from "lucide-react"; import { BookOpen, Check, ChevronRight, Download, Eye, FileText, Image as ImageIcon, ListChecks, Music2, Plus, Search, Settings2, Square, Trash2, Type, Video } from "lucide-react";
@@ -286,7 +286,7 @@ function buildInsertPayload(asset: Asset): InsertAssetPayload {
return { kind: "image", dataUrl: asset.data.dataUrl, storageKey: asset.data.storageKey, title: asset.title }; return { kind: "image", dataUrl: asset.data.dataUrl, storageKey: asset.data.storageKey, title: asset.title };
} }
function CanvasAssetsTab({ onInsert, theme }: { onInsert: (payload: InsertAssetPayload) => void; theme: CanvasTheme }) { const CanvasAssetsTab = memo(function CanvasAssetsTab({ onInsert, theme }: { onInsert: (payload: InsertAssetPayload) => void; theme: CanvasTheme }) {
const { message } = App.useApp(); const { message } = App.useApp();
const assets = useAssetStore((state) => state.assets); const assets = useAssetStore((state) => state.assets);
const addAsset = useAssetStore((state) => state.addAsset); const addAsset = useAssetStore((state) => state.addAsset);
@@ -398,7 +398,7 @@ function CanvasAssetsTab({ onInsert, theme }: { onInsert: (payload: InsertAssetP
</div> </div>
</div> </div>
); );
} });
function AssetCard({ asset, theme, onInsert, onRemove }: { asset: Asset; theme: CanvasTheme; onInsert: () => void; onRemove: () => void }) { function AssetCard({ asset, theme, onInsert, onRemove }: { asset: Asset; theme: CanvasTheme; onInsert: () => void; onRemove: () => void }) {
return ( return (
@@ -440,7 +440,7 @@ function AssetCover({ asset }: { asset: Asset }) {
// 提示词库 Tab —— 按来源折叠分组,展开时按需加载,点击复制 / 插入文本节点 // 提示词库 Tab —— 按来源折叠分组,展开时按需加载,点击复制 / 插入文本节点
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function CanvasPromptsTab({ onInsert, theme }: { onInsert: (payload: InsertAssetPayload) => void; theme: CanvasTheme }) { const CanvasPromptsTab = memo(function CanvasPromptsTab({ onInsert, theme }: { onInsert: (payload: InsertAssetPayload) => void; theme: CanvasTheme }) {
const { message } = App.useApp(); const { message } = App.useApp();
const sources = usePromptSourceStore((state) => state.sources); const sources = usePromptSourceStore((state) => state.sources);
const enabledSources = useMemo(() => sources.filter((source) => source.enabled), [sources]); const enabledSources = useMemo(() => sources.filter((source) => source.enabled), [sources]);
@@ -486,7 +486,7 @@ function CanvasPromptsTab({ onInsert, theme }: { onInsert: (payload: InsertAsset
<PromptDetailDialog prompt={detail} onClose={() => setDetail(null)} onCopy={(prompt) => void copyPrompt(prompt)} /> <PromptDetailDialog prompt={detail} onClose={() => setDetail(null)} onCopy={(prompt) => void copyPrompt(prompt)} />
</div> </div>
); );
} });
function PromptSourceGroup({ function PromptSourceGroup({
sourceId, sourceId,