# v4.1 第二轮代码清理 — 实现计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. **Goal:** 修复第二轮深度审查发现的 7 个代码质量问题 **Architecture:** 7 个独立小修,互不冲突。PathTable.tsx 有 3 项相关改动,放在一个 Task 里。 **Tech Stack:** TypeScript strict + React + Rust + Tauri IPC --- ### Task 1: PathTable 三合一(并发限制 + 双重触发 + 类型断言) **Files:** - Modify: `src/components/path-list/PathTable.tsx:25, 53, 78, 88-96, 111, 121` - [ ] **Step 1: 提取 `DEFAULT_VALIDATION_STATE` 常量,消除类型断言** ```typescript // 在组件外部定义(文件顶部 import 之后) const DEFAULT_VALIDATION_STATE: ValidationState = 'valid'; ``` 第 121 行改为: ```typescript state: validationCache.get(path) ?? DEFAULT_VALIDATION_STATE, ``` - [ ] **Step 2: 环境变量展开加 20 并发上限** 第 88-96 行,在 `toExpand` 之后加批次限制: ```typescript const toExpand = paths.filter( (p) => p.includes('%') && !expandedCache.has(p), ); if (toExpand.length === 0) return; const batch = toExpand.slice(0, 20); // ← 新增:限制并发 20 Promise.all( batch.map(async (p): Promise<[string, string]> => { ``` - [ ] **Step 3: 消除 useEffect 双重触发** 问题:`validationCache` 和 `expandedCache` 在依赖数组中,setState 后触发 effect 再次执行(空跑一轮)。 用 ref 跟踪"是否已经触发过验证",effect 只依赖 `paths`: ```typescript // 新增两个 ref(放在 useState 声明之后) const validatedRef = useRef>(new Set()); const expandedRef = useRef>(new Set()); ``` 验证 effect 改为: ```typescript useEffect(() => { let cancelled = false; const toValidate = paths.filter((p) => !validatedRef.current.has(p)); if (toValidate.length === 0) return; const batch = toValidate.slice(0, 20); Promise.all( batch.map(async (p): Promise<[string, ValidationState]> => { try { if (p.includes('%')) return [p, 'valid']; const valid: boolean = await invoke('validate_path', { path: p }); return [p, valid ? 'valid' : 'invalid']; } catch { return [p, 'unknown']; } }), ).then((results) => { if (cancelled) return; for (const [p] of results) validatedRef.current.add(p); setValidationCache((prev) => { const next = new Map(prev); for (const [p, v] of results) next.set(p, v); return next; }); }); return () => { cancelled = true; }; }, [paths]); // ← 移除 validationCache 依赖 ``` 展开 effect 同理: ```typescript useEffect(() => { let cancelled = false; const toExpand = paths.filter((p) => p.includes('%') && !expandedRef.current.has(p)); if (toExpand.length === 0) return; const batch = toExpand.slice(0, 20); Promise.all( batch.map(async (p): Promise<[string, string]> => { try { const expanded: string = await invoke('expand_env_vars', { path: p }); return [p, expanded !== p ? expanded : '']; } catch { return [p, '']; } }), ).then((results) => { if (cancelled) return; for (const [p] of results) expandedRef.current.add(p); setExpandedCache((prev) => { const next = new Map(prev); for (const [p, v] of results) next.set(p, v); return next; }); }); return () => { cancelled = true; }; }, [paths]); // ← 移除 expandedCache 依赖 ``` `validations` 和渲染逻辑不变。 - [ ] **Step 4: 添加 `useRef` 到 import** ```typescript // 第 1 行 import { useState, useEffect, useMemo, useCallback, useRef } from 'react'; ``` - [ ] **Step 5: 编译 + 测试** ```bash npx tsc --noEmit && npx vitest run ``` - [ ] **Step 6: Commit** ```bash git add src/components/path-list/PathTable.tsx git commit -m "fix: PathTable — 环境变量展开限流20并发、消除useEffect双重触发、类型断言改为常量" ``` --- ### Task 2: backup.rs — use 语句移到文件顶部 + 消除路径字符串重复 **Files:** - Modify: `src-tauri/src/commands/registry.rs:4-5` - Modify: `src-tauri/src/commands/backup.rs:1-3, 22-23, 34-42` - [ ] **Step 1: registry.rs 常量改为 pub(crate)** ```rust // src-tauri/src/commands/registry.rs — 第 4-5 行,加 pub(crate) pub(crate) const SYS_REG_PATH: &str = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"; pub(crate) const USER_REG_PATH: &str = "Environment"; pub(crate) const PATH_VALUE: &str = "Path"; ``` - [ ] **Step 2: backup.rs — 移动 use 到文件顶部,消除重复字符串** ```rust // src-tauri/src/commands/backup.rs — 文件顶部(第 1 行之后) use chrono::Local; use std::path::PathBuf; use winreg::enums::*; // ← 从函数体内移出 // 第 4 行之后新增: use crate::commands::registry::{self, SYS_REG_PATH, USER_REG_PATH}; ``` 删除函数体内的 `use`(第 22-23 行),更新路径引用: ```rust // backup.rs — 第 34-42 行,用常量替换字符串字面量 let sys_paths = registry::load_paths( HKEY_LOCAL_MACHINE, SYS_REG_PATH, // ← 用常量 "系统", )?; let user_paths = registry::load_paths( HKEY_CURRENT_USER, USER_REG_PATH, // ← 用常量 "用户", )?; ``` - [ ] **Step 3: 编译 + clippy** ```bash cd src-tauri && cargo check && cargo clippy -- -D warnings ``` - [ ] **Step 4: Commit** ```bash git add src-tauri/src/commands/registry.rs src-tauri/src/commands/backup.rs git commit -m "refactor: backup.rs — use 语句移至文件顶部,注册表路径复用常量消除重复" ``` --- ### Task 3: AppShell — `as any` 拖拽路径类型安全 **Files:** - Modify: `src/components/layout/AppShell.tsx:95` - [ ] **Step 1: 定义 TauriFile 接口并消除 as any** 在 AppShell 组件定义之前(第 16 行之后)加: ```typescript /** Tauri 的 File 对象扩展了标准 File,额外提供文件系统路径 */ interface TauriFile extends File { path: string; } ``` 第 95 行改为: ```typescript const file = e.dataTransfer.files[i] as TauriFile; if (file.path) useAppStore.getState().addPath(file.path, activeTab === 'user' ? TargetType.USER : TargetType.SYSTEM); ``` - [ ] **Step 2: 编译检查** ```bash npx tsc --noEmit ``` - [ ] **Step 3: Commit** ```bash git add src/components/layout/AppShell.tsx git commit -m "fix: AppShell 拖拽路径消除 as any,用 TauriFile 接口类型安全访问 path" ``` --- ### Task 4: app-store — undo/redo 加注释说明为何不用 markDirty() **Files:** - Modify: `src/store/app-store.ts:210-226` - [ ] **Step 1: 在 undo/redo 的 isModified 行添加注释** ```typescript // app-store.ts — 第 213 行之前加注释 undo: () => { const { undoRedo, sysPaths, userPaths, _savedSys, _savedUser } = get(); const result = undoRedo.undo(sysPaths, userPaths); if (result) { set({ sysPaths: result[0], userPaths: result[1], selectedIndices: [], // 内联 isModified 计算而非调用 markDirty(),避免两次 set() 渲染 isModified: !(arraysEqual(result[0], _savedSys) && arraysEqual(result[1], _savedUser)), }); } }, redo: () => { const { undoRedo, sysPaths, userPaths, _savedSys, _savedUser } = get(); const result = undoRedo.redo(sysPaths, userPaths); if (result) { set({ sysPaths: result[0], userPaths: result[1], selectedIndices: [], // 内联 isModified 计算而非调用 markDirty(),避免两次 set() 渲染 isModified: !(arraysEqual(result[0], _savedSys) && arraysEqual(result[1], _savedUser)), }); } }, ``` - [ ] **Step 2: 编译检查** ```bash npx tsc --noEmit ``` - [ ] **Step 3: Commit** ```bash git add src/store/app-store.ts git commit -m "docs: undo/redo 添加注释说明为何内联 isModified 而非调用 markDirty()" ``` --- ## 执行顺序 Task 1 → 2 → 3 → 4,互不依赖但建议按序执行。 全部完成后运行完整验证: ```bash npx tsc --noEmit && npx vitest run && cd src-tauri && cargo check && cargo clippy -- -D warnings ```