From cf5e8491df2f18d2fe173f159f06747cb8462915 Mon Sep 17 00:00:00 2001 From: yyh Date: Tue, 20 Jan 2026 15:54:31 +0800 Subject: [PATCH] chore: optimize code quality and performance --- .../skill/file-tree/tree-guide-lines.tsx | 27 ++++++++++--------- .../skill/hooks/use-create-operations.ts | 18 +++++++------ .../workflow/skill/hooks/use-delayed-click.ts | 10 ++++++- .../skill/hooks/use-paste-operation.ts | 16 ++++++----- .../skill/hooks/use-tree-node-handlers.ts | 8 +++--- 5 files changed, 47 insertions(+), 32 deletions(-) diff --git a/web/app/components/workflow/skill/file-tree/tree-guide-lines.tsx b/web/app/components/workflow/skill/file-tree/tree-guide-lines.tsx index 873f6b3d07..49b78b8bc6 100644 --- a/web/app/components/workflow/skill/file-tree/tree-guide-lines.tsx +++ b/web/app/components/workflow/skill/file-tree/tree-guide-lines.tsx @@ -1,6 +1,7 @@ 'use client' import * as React from 'react' +import { useMemo } from 'react' type TreeGuideLinesProps = { level: number @@ -16,20 +17,20 @@ const TreeGuideLines: React.FC = ({ indentSize = INDENT_SIZE, lineOffset = DEFAULT_LINE_OFFSET, }) => { - if (level === 0) - return null + const guides = useMemo(() => { + if (level === 0) + return null - return ( - <> - {Array.from({ length: level }).map((_, i) => ( -
- ))} - - ) + return Array.from({ length: level }, (_, i) => ( +
+ )) + }, [level, indentSize, lineOffset]) + + return guides } export default React.memo(TreeGuideLines) diff --git a/web/app/components/workflow/skill/hooks/use-create-operations.ts b/web/app/components/workflow/skill/hooks/use-create-operations.ts index e0a3dba105..3642deb324 100644 --- a/web/app/components/workflow/skill/hooks/use-create-operations.ts +++ b/web/app/components/workflow/skill/hooks/use-create-operations.ts @@ -50,14 +50,16 @@ export function useCreateOperations({ } try { - for (const file of files) { - await createFile.mutateAsync({ - appId, - name: file.name, - file, - parentId, - }) - } + await Promise.all( + files.map(file => + createFile.mutateAsync({ + appId, + name: file.name, + file, + parentId, + }), + ), + ) Toast.notify({ type: 'success', diff --git a/web/app/components/workflow/skill/hooks/use-delayed-click.ts b/web/app/components/workflow/skill/hooks/use-delayed-click.ts index c9db588391..4fbad745ea 100644 --- a/web/app/components/workflow/skill/hooks/use-delayed-click.ts +++ b/web/app/components/workflow/skill/hooks/use-delayed-click.ts @@ -1,4 +1,4 @@ -import { useCallback, useRef } from 'react' +import { useCallback, useEffect, useRef } from 'react' type UseDelayedClickOptions = { delay?: number @@ -18,6 +18,14 @@ export function useDelayedClick({ }: UseDelayedClickOptions) { const timeoutRef = useRef(null) + // Cleanup timeout on unmount to prevent state updates on unmounted components + useEffect(() => { + return () => { + if (timeoutRef.current) + clearTimeout(timeoutRef.current) + } + }, []) + const handleClick = useCallback(() => { if (timeoutRef.current) clearTimeout(timeoutRef.current) diff --git a/web/app/components/workflow/skill/hooks/use-paste-operation.ts b/web/app/components/workflow/skill/hooks/use-paste-operation.ts index bfba76ecbb..e53b2ef6de 100644 --- a/web/app/components/workflow/skill/hooks/use-paste-operation.ts +++ b/web/app/components/workflow/skill/hooks/use-paste-operation.ts @@ -73,13 +73,15 @@ export function usePasteOperation({ isPastingRef.current = true try { - for (const nodeId of nodeIdsArray) { - await moveNode.mutateAsync({ - appId, - nodeId, - payload: { parent_id: targetParentId }, - }) - } + await Promise.all( + nodeIdsArray.map(nodeId => + moveNode.mutateAsync({ + appId, + nodeId, + payload: { parent_id: targetParentId }, + }), + ), + ) storeApi.getState().clearClipboard() diff --git a/web/app/components/workflow/skill/hooks/use-tree-node-handlers.ts b/web/app/components/workflow/skill/hooks/use-tree-node-handlers.ts index 602bb5d857..90a0e11b86 100644 --- a/web/app/components/workflow/skill/hooks/use-tree-node-handlers.ts +++ b/web/app/components/workflow/skill/hooks/use-tree-node-handlers.ts @@ -3,7 +3,7 @@ import type { NodeApi } from 'react-arborist' import type { TreeNodeData } from '../type' import { throttle } from 'es-toolkit/function' -import { useCallback, useMemo } from 'react' +import { useCallback, useMemo, useRef } from 'react' import { useWorkflowStore } from '@/app/components/workflow/store' import { useDelayedClick } from './use-delayed-click' @@ -24,10 +24,12 @@ export function useTreeNodeHandlers({ }: UseTreeNodeHandlersOptions): UseTreeNodeHandlersReturn { const storeApi = useWorkflowStore() const isFolder = node.data.node_type === 'folder' + const nodeRef = useRef(node) + nodeRef.current = node const throttledToggle = useMemo( - () => throttle(() => node.toggle(), 300, { edges: ['leading'] }), - [node], + () => throttle(() => nodeRef.current.toggle(), 300, { edges: ['leading'] }), + [], ) const openFilePreview = useCallback(() => {