diff --git a/web/app/components/workflow/skill/start-tab/skill-templates-section.tsx b/web/app/components/workflow/skill/start-tab/skill-templates-section.tsx index a48fe3e777..222239f9d0 100644 --- a/web/app/components/workflow/skill/start-tab/skill-templates-section.tsx +++ b/web/app/components/workflow/skill/start-tab/skill-templates-section.tsx @@ -1,7 +1,7 @@ 'use client' import type { SkillTemplateSummary } from './templates/types' -import { memo, useCallback, useState } from 'react' +import { memo, useCallback, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import { useStore as useAppStore } from '@/app/components/app/store' import { useWorkflowStore } from '@/app/components/workflow/store' @@ -24,7 +24,11 @@ const SkillTemplatesSection = () => { const appId = appDetail?.id || '' const storeApi = useWorkflowStore() const batchUpload = useBatchUpload() + const batchUploadRef = useRef(batchUpload) + batchUploadRef.current = batchUpload const emitTreeUpdate = useSkillTreeUpdateEmitter() + const emitTreeUpdateRef = useRef(emitTreeUpdate) + emitTreeUpdateRef.current = emitTreeUpdate const handleUse = useCallback(async (summary: SkillTemplateSummary) => { const entry = SKILL_TEMPLATES.find(e => e.id === summary.id) @@ -39,7 +43,7 @@ const SkillTemplatesSection = () => { const children = await entry.loadContent() const uploadData = await buildUploadDataFromTemplate(summary.name, children) - await batchUpload.mutateAsync({ + await batchUploadRef.current.mutateAsync({ appId, tree: uploadData.tree, files: uploadData.files, @@ -50,7 +54,7 @@ const SkillTemplatesSection = () => { }) storeApi.getState().setUploadStatus('success') - emitTreeUpdate() + emitTreeUpdateRef.current() } catch { storeApi.getState().setUploadStatus('partial_error') @@ -58,9 +62,9 @@ const SkillTemplatesSection = () => { finally { setLoadingId(null) } - }, [appId, batchUpload, storeApi, emitTreeUpdate]) + }, [appId, storeApi]) - const filtered = SKILL_TEMPLATES.filter((entry) => { + const filtered = useMemo(() => SKILL_TEMPLATES.filter((entry) => { if (searchValue) { const q = searchValue.toLowerCase() return entry.name.toLowerCase().includes(q) || entry.description.toLowerCase().includes(q) @@ -68,7 +72,7 @@ const SkillTemplatesSection = () => { if (activeCategory !== 'all') return entry.tags?.some(tag => tag.toLowerCase() === activeCategory.toLowerCase()) return true - }) + }), [searchValue, activeCategory]) return (
@@ -95,9 +99,9 @@ const SkillTemplatesSection = () => { /> ))} - {loadingId && ( -
- )} + {loadingId + ?
+ : null}
) }