component-refactoring
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDify Component Refactoring Skill
Dify 组件重构技能
Refactor high-complexity React components in the Dify frontend codebase with the patterns and workflow below.
Complexity Threshold: Components with complexity > 50 (measured by) should be refactored before testing.pnpm analyze-component
按照以下模式和工作流,重构Dify前端代码库中的高复杂度React组件。
复杂度阈值:测得复杂度>50的组件需在测试前完成重构。pnpm analyze-component
Quick Reference
快速参考
Commands (run from web/
)
web/命令(从web/
目录执行)
web/Use paths relative to (e.g., ).
Use for refactoring prompts and for testing prompts and metrics.
web/app/components/...refactor-componentanalyze-componentbash
cd web使用相对于的路径(例如)。
使用生成重构提示,使用生成测试提示和指标。
web/app/components/...refactor-componentanalyze-componentbash
cd webGenerate refactoring prompt
生成重构提示
pnpm refactor-component <path>
pnpm refactor-component <path>
Output refactoring analysis as JSON
以JSON格式输出重构分析结果
pnpm refactor-component <path> --json
pnpm refactor-component <path> --json
Generate testing prompt (after refactoring)
生成测试提示(重构后执行)
pnpm analyze-component <path>
pnpm analyze-component <path>
Output testing analysis as JSON
以JSON格式输出测试分析结果
pnpm analyze-component <path> --json
undefinedpnpm analyze-component <path> --json
undefinedComplexity Analysis
复杂度分析
bash
undefinedbash
undefinedAnalyze component complexity
分析组件复杂度
pnpm analyze-component <path> --json
pnpm analyze-component <path> --json
Key metrics to check:
需要关注的关键指标:
- complexity: normalized score 0-100 (target < 50)
- complexity: 标准化分数0-100(目标<50)
- maxComplexity: highest single function complexity
- maxComplexity: 单个函数的最高复杂度
- lineCount: total lines (target < 300)
- lineCount: 总代码行数(目标<300)
undefinedundefinedComplexity Score Interpretation
复杂度分数解读
| Score | Level | Action |
|---|---|---|
| 0-25 | 🟢 Simple | Ready for testing |
| 26-50 | 🟡 Medium | Consider minor refactoring |
| 51-75 | 🟠 Complex | Refactor before testing |
| 76-100 | 🔴 Very Complex | Must refactor |
| 分数 | 级别 | 操作建议 |
|---|---|---|
| 0-25 | 🟢 简单 | 可直接测试 |
| 26-50 | 🟡 中等 | 考虑小幅重构 |
| 51-75 | 🟠 复杂 | 测试前必须重构 |
| 76-100 | 🔴 极高复杂度 | 必须重构 |
Core Refactoring Patterns
核心重构模式
Pattern 1: Extract Custom Hooks
模式1:提取自定义Hook
When: Component has complex state management, multiple /, or business logic mixed with UI.
useStateuseEffectDify Convention: Place hooks in a subdirectory or alongside the component as .
hooks/use-<feature>.tstypescript
// ❌ Before: Complex state logic in component
const Configuration: FC = () => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [datasetConfigs, setDatasetConfigs] = useState<DatasetConfigs>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
// 50+ lines of state management logic...
return <div>...</div>
}
// ✅ After: Extract to custom hook
// hooks/use-model-config.ts
export const useModelConfig = (appId: string) => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
// Related state management logic here
return { modelConfig, setModelConfig, completionParams, setCompletionParams }
}
// Component becomes cleaner
const Configuration: FC = () => {
const { modelConfig, setModelConfig } = useModelConfig(appId)
return <div>...</div>
}Dify Examples:
web/app/components/app/configuration/hooks/use-advanced-prompt-config.tsweb/app/components/app/configuration/debug/hooks.tsxweb/app/components/workflow/hooks/use-workflow.ts
适用场景:组件包含复杂状态管理、多个/,或业务逻辑与UI代码混合。
useStateuseEffectDify 约定:将Hook放置在子目录中,或与组件同级命名为。
hooks/use-<feature>.tstypescript
// ❌ 重构前:组件内包含复杂状态逻辑
const Configuration: FC = () => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [datasetConfigs, setDatasetConfigs] = useState<DatasetConfigs>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
// 50+行状态管理逻辑...
return <div>...</div>
}
// ✅ 重构后:提取为自定义Hook
// hooks/use-model-config.ts
export const useModelConfig = (appId: string) => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
// 相关状态管理逻辑在此处
return { modelConfig, setModelConfig, completionParams, setCompletionParams }
}
// 组件变得更简洁
const Configuration: FC = () => {
const { modelConfig, setModelConfig } = useModelConfig(appId)
return <div>...</div>
}Dify 示例:
web/app/components/app/configuration/hooks/use-advanced-prompt-config.tsweb/app/components/app/configuration/debug/hooks.tsxweb/app/components/workflow/hooks/use-workflow.ts
Pattern 2: Extract Sub-Components
模式2:提取子组件
When: Single component has multiple UI sections, conditional rendering blocks, or repeated patterns.
Dify Convention: Place sub-components in subdirectories or as separate files in the same directory.
typescript
// ❌ Before: Monolithic JSX with multiple sections
const AppInfo = () => {
return (
<div>
{/* 100 lines of header UI */}
{/* 100 lines of operations UI */}
{/* 100 lines of modals */}
</div>
)
}
// ✅ After: Split into focused components
// app-info/
// ├── index.tsx (orchestration only)
// ├── app-header.tsx (header UI)
// ├── app-operations.tsx (operations UI)
// └── app-modals.tsx (modal management)
const AppInfo = () => {
const { showModal, setShowModal } = useAppInfoModals()
return (
<div>
<AppHeader appDetail={appDetail} />
<AppOperations onAction={handleAction} />
<AppModals show={showModal} onClose={() => setShowModal(null)} />
</div>
)
}Dify Examples:
- directory structure
web/app/components/app/configuration/ - per-node organization
web/app/components/workflow/nodes/
适用场景:单个组件包含多个UI区块、条件渲染块或重复代码模式。
Dify 约定:将子组件放置在子目录中,或与组件同级分为独立文件。
typescript
// ❌ 重构前:包含多个区块的单体JSX
const AppInfo = () => {
return (
<div>
{/* 100行头部UI代码 */}
{/* 100行操作区UI代码 */}
{/* 100行模态框代码 */}
</div>
)
}
// ✅ 重构后:拆分为专注单一职责的组件
// app-info/
// ├── index.tsx (仅负责组件编排)
// ├── app-header.tsx (头部UI)
// ├── app-operations.tsx (操作区UI)
// └── app-modals.tsx (模态框管理)
const AppInfo = () => {
const { showModal, setShowModal } = useAppInfoModals()
return (
<div>
<AppHeader appDetail={appDetail} />
<AppOperations onAction={handleAction} />
<AppModals show={showModal} onClose={() => setShowModal(null)} />
</div>
)
}Dify 示例:
- 目录结构
web/app/components/app/configuration/ - 按节点类型组织
web/app/components/workflow/nodes/
Pattern 3: Simplify Conditional Logic
模式3:简化条件逻辑
When: Deep nesting (> 3 levels), complex ternaries, or multiple chains.
if/elsetypescript
// ❌ Before: Deeply nested conditionals
const Template = useMemo(() => {
if (appDetail?.mode === AppModeEnum.CHAT) {
switch (locale) {
case LanguagesSupported[1]:
return <TemplateChatZh />
case LanguagesSupported[7]:
return <TemplateChatJa />
default:
return <TemplateChatEn />
}
}
if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {
// Another 15 lines...
}
// More conditions...
}, [appDetail, locale])
// ✅ After: Use lookup tables + early returns
const TEMPLATE_MAP = {
[AppModeEnum.CHAT]: {
[LanguagesSupported[1]]: TemplateChatZh,
[LanguagesSupported[7]]: TemplateChatJa,
default: TemplateChatEn,
},
[AppModeEnum.ADVANCED_CHAT]: {
[LanguagesSupported[1]]: TemplateAdvancedChatZh,
// ...
},
}
const Template = useMemo(() => {
const modeTemplates = TEMPLATE_MAP[appDetail?.mode]
if (!modeTemplates) return null
const TemplateComponent = modeTemplates[locale] || modeTemplates.default
return <TemplateComponent appDetail={appDetail} />
}, [appDetail, locale])适用场景:深层嵌套(>3层)、复杂三元表达式,或多个链式判断。
if/elsetypescript
// ❌ 重构前:深层嵌套条件
const Template = useMemo(() => {
if (appDetail?.mode === AppModeEnum.CHAT) {
switch (locale) {
case LanguagesSupported[1]:
return <TemplateChatZh />
case LanguagesSupported[7]:
return <TemplateChatJa />
default:
return <TemplateChatEn />
}
}
if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {
// 另外15行代码...
}
// 更多条件判断...
}, [appDetail, locale])
// ✅ 重构后:使用查找表+提前返回
const TEMPLATE_MAP = {
[AppModeEnum.CHAT]: {
[LanguagesSupported[1]]: TemplateChatZh,
[LanguagesSupported[7]]: TemplateChatJa,
default: TemplateChatEn,
},
[AppModeEnum.ADVANCED_CHAT]: {
[LanguagesSupported[1]]: TemplateAdvancedChatZh,
// ...
},
}
const Template = useMemo(() => {
const modeTemplates = TEMPLATE_MAP[appDetail?.mode]
if (!modeTemplates) return null
const TemplateComponent = modeTemplates[locale] || modeTemplates.default
return <TemplateComponent appDetail={appDetail} />
}, [appDetail, locale])Pattern 4: Extract API/Data Logic
模式4:提取API/数据逻辑
When: Component directly handles API calls, data transformation, or complex async operations.
Dify Convention: Use hooks from or create custom data hooks.
@tanstack/react-queryweb/service/use-*.tstypescript
// ❌ Before: API logic in component
const MCPServiceCard = () => {
const [basicAppConfig, setBasicAppConfig] = useState({})
useEffect(() => {
if (isBasicApp && appId) {
(async () => {
const res = await fetchAppDetail({ url: '/apps', id: appId })
setBasicAppConfig(res?.model_config || {})
})()
}
}, [appId, isBasicApp])
// More API-related logic...
}
// ✅ After: Extract to data hook using React Query
// use-app-config.ts
import { useQuery } from '@tanstack/react-query'
import { get } from '@/service/base'
const NAME_SPACE = 'appConfig'
export const useAppConfig = (appId: string, isBasicApp: boolean) => {
return useQuery({
enabled: isBasicApp && !!appId,
queryKey: [NAME_SPACE, 'detail', appId],
queryFn: () => get<AppDetailResponse>(`/apps/${appId}`),
select: data => data?.model_config || {},
})
}
// Component becomes cleaner
const MCPServiceCard = () => {
const { data: config, isLoading } = useAppConfig(appId, isBasicApp)
// UI only
}React Query Best Practices in Dify:
- Define for query key organization
NAME_SPACE - Use option for conditional fetching
enabled - Use for data transformation
select - Export invalidation hooks:
useInvalidXxx
Dify Examples:
web/service/use-workflow.tsweb/service/use-common.tsweb/service/knowledge/use-dataset.tsweb/service/knowledge/use-document.ts
适用场景:组件直接处理API调用、数据转换或复杂异步操作。
Dify 约定:使用中的 Hook,或创建自定义数据Hook。
web/service/use-*.ts@tanstack/react-querytypescript
// ❌ 重构前:组件内包含API逻辑
const MCPServiceCard = () => {
const [basicAppConfig, setBasicAppConfig] = useState({})
useEffect(() => {
if (isBasicApp && appId) {
(async () => {
const res = await fetchAppDetail({ url: '/apps', id: appId })
setBasicAppConfig(res?.model_config || {})
})()
}
}, [appId, isBasicApp])
// 更多API相关逻辑...
}
// ✅ 重构后:使用React Query提取为数据Hook
// use-app-config.ts
import { useQuery } from '@tanstack/react-query'
import { get } from '@/service/base'
const NAME_SPACE = 'appConfig'
export const useAppConfig = (appId: string, isBasicApp: boolean) => {
return useQuery({
enabled: isBasicApp && !!appId,
queryKey: [NAME_SPACE, 'detail', appId],
queryFn: () => get<AppDetailResponse>(`/apps/${appId}`),
select: data => data?.model_config || {},
})
}
// 组件变得更简洁
const MCPServiceCard = () => {
const { data: config, isLoading } = useAppConfig(appId, isBasicApp)
// 仅保留UI代码
}Dify 中的React Query最佳实践:
- 为查询键定义以优化组织
NAME_SPACE - 使用选项实现条件式数据获取
enabled - 使用进行数据转换
select - 导出失效Hook:
useInvalidXxx
Dify 示例:
web/service/use-workflow.tsweb/service/use-common.tsweb/service/knowledge/use-dataset.tsweb/service/knowledge/use-document.ts
Pattern 5: Extract Modal/Dialog Management
模式5:提取模态框/对话框管理逻辑
When: Component manages multiple modals with complex open/close states.
Dify Convention: Modals should be extracted with their state management.
typescript
// ❌ Before: Multiple modal states in component
const AppInfo = () => {
const [showEditModal, setShowEditModal] = useState(false)
const [showDuplicateModal, setShowDuplicateModal] = useState(false)
const [showConfirmDelete, setShowConfirmDelete] = useState(false)
const [showSwitchModal, setShowSwitchModal] = useState(false)
const [showImportDSLModal, setShowImportDSLModal] = useState(false)
// 5+ more modal states...
}
// ✅ After: Extract to modal management hook
type ModalType = 'edit' | 'duplicate' | 'delete' | 'switch' | 'import' | null
const useAppInfoModals = () => {
const [activeModal, setActiveModal] = useState<ModalType>(null)
const openModal = useCallback((type: ModalType) => setActiveModal(type), [])
const closeModal = useCallback(() => setActiveModal(null), [])
return {
activeModal,
openModal,
closeModal,
isOpen: (type: ModalType) => activeModal === type,
}
}适用场景:组件管理多个模态框,且包含复杂的显示/隐藏状态。
Dify 约定:模态框应与其状态管理逻辑一起提取。
typescript
// ❌ 重构前:组件内包含多个模态框状态
const AppInfo = () => {
const [showEditModal, setShowEditModal] = useState(false)
const [showDuplicateModal, setShowDuplicateModal] = useState(false)
const [showConfirmDelete, setShowConfirmDelete] = useState(false)
const [showSwitchModal, setShowSwitchModal] = useState(false)
const [showImportDSLModal, setShowImportDSLModal] = useState(false)
// 5+个其他模态框状态...
}
// ✅ 重构后:提取为模态框管理Hook
type ModalType = 'edit' | 'duplicate' | 'delete' | 'switch' | 'import' | null
const useAppInfoModals = () => {
const [activeModal, setActiveModal] = useState<ModalType>(null)
const openModal = useCallback((type: ModalType) => setActiveModal(type), [])
const closeModal = useCallback(() => setActiveModal(null), [])
return {
activeModal,
openModal,
closeModal,
isOpen: (type: ModalType) => activeModal === type,
}
}Pattern 6: Extract Form Logic
模式6:提取表单逻辑
When: Complex form validation, submission handling, or field transformation.
Dify Convention: Use patterns from .
@tanstack/react-formweb/app/components/base/form/typescript
// ✅ Use existing form infrastructure
import { useAppForm } from '@/app/components/base/form'
const ConfigForm = () => {
const form = useAppForm({
defaultValues: { name: '', description: '' },
onSubmit: handleSubmit,
})
return <form.Provider>...</form.Provider>
}适用场景:复杂表单验证、提交处理或字段转换。
Dify 约定:使用中的模式。
web/app/components/base/form/@tanstack/react-formtypescript
// ✅ 使用现有表单基础设施
import { useAppForm } from '@/app/components/base/form'
const ConfigForm = () => {
const form = useAppForm({
defaultValues: { name: '', description: '' },
onSubmit: handleSubmit,
})
return <form.Provider>...</form.Provider>
}Dify-Specific Refactoring Guidelines
Dify 专属重构指南
1. Context Provider Extraction
1. Context Provider 提取
When: Component provides complex context values with multiple states.
typescript
// ❌ Before: Large context value object
const value = {
appId, isAPIKeySet, isTrailFinished, mode, modelModeType,
promptMode, isAdvancedMode, isAgent, isOpenAI, isFunctionCall,
// 50+ more properties...
}
return <ConfigContext.Provider value={value}>...</ConfigContext.Provider>
// ✅ After: Split into domain-specific contexts
<ModelConfigProvider value={modelConfigValue}>
<DatasetConfigProvider value={datasetConfigValue}>
<UIConfigProvider value={uiConfigValue}>
{children}
</UIConfigProvider>
</DatasetConfigProvider>
</ModelConfigProvider>Dify Reference: directory structure
web/context/适用场景:组件提供包含多个状态的复杂Context值。
typescript
// ❌ 重构前:庞大的Context值对象
const value = {
appId, isAPIKeySet, isTrailFinished, mode, modelModeType,
promptMode, isAdvancedMode, isAgent, isOpenAI, isFunctionCall,
// 50+个其他属性...
}
return <ConfigContext.Provider value={value}>...</ConfigContext.Provider>
// ✅ 重构后:拆分为领域专属Context
<ModelConfigProvider value={modelConfigValue}>
<DatasetConfigProvider value={datasetConfigValue}>
<UIConfigProvider value={uiConfigValue}>
{children}
</UIConfigProvider>
</DatasetConfigProvider>
</ModelConfigProvider>Dify 参考:目录结构
web/context/2. Workflow Node Components
2. 工作流节点组件
When: Refactoring workflow node components ().
web/app/components/workflow/nodes/Conventions:
- Keep node logic in
use-interactions.ts - Extract panel UI to separate files
- Use components for common patterns
_base
nodes/<node-type>/
├── index.tsx # Node registration
├── node.tsx # Node visual component
├── panel.tsx # Configuration panel
├── use-interactions.ts # Node-specific hooks
└── types.ts # Type definitions适用场景:重构工作流节点组件()。
web/app/components/workflow/nodes/约定:
- 将节点逻辑放置在中
use-interactions.ts - 将面板UI提取到独立文件
- 使用组件实现通用模式
_base
nodes/<node-type>/
├── index.tsx # 节点注册
├── node.tsx # 节点可视化组件
├── panel.tsx # 配置面板
├── use-interactions.ts # 节点专属Hook
└── types.ts # 类型定义3. Configuration Components
3. 配置组件
When: Refactoring app configuration components.
Conventions:
- Separate config sections into subdirectories
- Use existing patterns from
web/app/components/app/configuration/ - Keep feature toggles in dedicated components
适用场景:重构应用配置组件。
约定:
- 将配置区块拆分为子目录
- 遵循中的现有模式
web/app/components/app/configuration/ - 将功能开关放置在专属组件中
4. Tool/Plugin Components
4. 工具/插件组件
When: Refactoring tool-related components ().
web/app/components/tools/Conventions:
- Follow existing modal patterns
- Use service hooks from
web/service/use-tools.ts - Keep provider-specific logic isolated
适用场景:重构工具相关组件()。
web/app/components/tools/约定:
- 遵循现有模态框模式
- 使用中的服务Hook
web/service/use-tools.ts - 隔离供应商专属逻辑
Refactoring Workflow
重构工作流
Step 1: Generate Refactoring Prompt
步骤1:生成重构提示
bash
pnpm refactor-component <path>This command will:
- Analyze component complexity and features
- Identify specific refactoring actions needed
- Generate a prompt for AI assistant (auto-copied to clipboard on macOS)
- Provide detailed requirements based on detected patterns
bash
pnpm refactor-component <path>该命令将:
- 分析组件复杂度和功能
- 识别需要执行的具体重构操作
- 生成AI助手提示(在macOS上自动复制到剪贴板)
- 根据检测到的模式提供详细要求
Step 2: Analyze Details
步骤2:分析细节
bash
pnpm analyze-component <path> --jsonIdentify:
- Total complexity score
- Max function complexity
- Line count
- Features detected (state, effects, API, etc.)
bash
pnpm analyze-component <path> --json识别以下内容:
- 总复杂度分数
- 单个函数的最高复杂度
- 代码行数
- 检测到的功能(状态、副作用、API等)
Step 3: Plan
步骤3:制定计划
Create a refactoring plan based on detected features:
| Detected Feature | Refactoring Action |
|---|---|
| Extract custom hook |
| Extract data/service hook |
| Extract event handlers |
| Split into sub-components |
| Simplify conditional logic |
根据检测到的功能制定重构计划:
| 检测到的功能 | 重构操作 |
|---|---|
| 提取自定义Hook |
| 提取数据/服务Hook |
| 提取事件处理器 |
| 拆分为子组件 |
| 简化条件逻辑 |
Step 4: Execute Incrementally
步骤4:增量执行
- Extract one piece at a time
- Run lint, type-check, and tests after each extraction
- Verify functionality before next step
For each extraction:
┌────────────────────────────────────────┐
│ 1. Extract code │
│ 2. Run: pnpm lint:fix │
│ 3. Run: pnpm type-check:tsgo │
│ 4. Run: pnpm test │
│ 5. Test functionality manually │
│ 6. PASS? → Next extraction │
│ FAIL? → Fix before continuing │
└────────────────────────────────────────┘- 每次只提取一部分代码
- 每次提取后运行lint、类型检查和测试
- 验证功能正常后再进行下一步
对于每一次提取:
┌────────────────────────────────────────┐
│ 1. 提取代码 │
│ 2. 执行:pnpm lint:fix │
│ 3. 执行:pnpm type-check:tsgo │
│ 4. 执行:pnpm test │
│ 5. 手动测试功能 │
│ 6. 通过?→ 进行下一次提取 │
│ 失败?→ 修复后再继续 │
└────────────────────────────────────────┘Step 5: Verify
步骤5:验证
After refactoring:
bash
undefined重构完成后:
bash
undefinedRe-run refactor command to verify improvements
重新运行重构命令验证改进效果
pnpm refactor-component <path>
pnpm refactor-component <path>
If complexity < 25 and lines < 200, you'll see:
如果复杂度<25且代码行数<200,你将看到:
✅ COMPONENT IS WELL-STRUCTURED
✅ COMPONENT IS WELL-STRUCTURED
For detailed metrics:
查看详细指标:
pnpm analyze-component <path> --json
pnpm analyze-component <path> --json
Target metrics:
目标指标:
- complexity < 50
- complexity < 50
- lineCount < 300
- lineCount < 300
- maxComplexity < 30
- maxComplexity < 30
undefinedundefinedCommon Mistakes to Avoid
需避免的常见错误
❌ Over-Engineering
❌ 过度设计
typescript
// ❌ Too many tiny hooks
const useButtonText = () => useState('Click')
const useButtonDisabled = () => useState(false)
const useButtonLoading = () => useState(false)
// ✅ Cohesive hook with related state
const useButtonState = () => {
const [text, setText] = useState('Click')
const [disabled, setDisabled] = useState(false)
const [loading, setLoading] = useState(false)
return { text, setText, disabled, setDisabled, loading, setLoading }
}typescript
// ❌ 过多微小的Hook
const useButtonText = () => useState('Click')
const useButtonDisabled = () => useState(false)
const useButtonLoading = () => useState(false)
// ✅ 内聚的Hook,包含相关状态
const useButtonState = () => {
const [text, setText] = useState('Click')
const [disabled, setDisabled] = useState(false)
const [loading, setLoading] = useState(false)
return { text, setText, disabled, setDisabled, loading, setLoading }
}❌ Breaking Existing Patterns
❌ 破坏现有模式
- Follow existing directory structures
- Maintain naming conventions
- Preserve export patterns for compatibility
- 遵循现有目录结构
- 保持命名约定
- 保留导出模式以确保兼容性
❌ Premature Abstraction
❌ 过早抽象
- Only extract when there's clear complexity benefit
- Don't create abstractions for single-use code
- Keep refactored code in the same domain area
- 仅当能明确降低复杂度时才进行提取
- 不为仅使用一次的代码创建抽象
- 保持重构后的代码在同一领域范围内
References
参考资料
Dify Codebase Examples
Dify 代码库示例
- Hook extraction:
web/app/components/app/configuration/hooks/ - Component splitting:
web/app/components/app/configuration/ - Service hooks:
web/service/use-*.ts - Workflow patterns:
web/app/components/workflow/hooks/ - Form patterns:
web/app/components/base/form/
- Hook 提取:
web/app/components/app/configuration/hooks/ - 组件拆分:
web/app/components/app/configuration/ - 服务Hook:
web/service/use-*.ts - 工作流模式:
web/app/components/workflow/hooks/ - 表单模式:
web/app/components/base/form/
Related Skills
相关技能
- - For testing refactored components
frontend-testing - - Testing specification
web/docs/test.md
- - 用于测试重构后的组件
frontend-testing - - 测试规范
web/docs/test.md