fix: 修复 ESLint set-state-in-effect 错误 — useEffect 加 prevOpen 守卫
CI / Rust 检查 (Check + Clippy + Test) (push) Has been cancelled
CI / 前端检查 (TypeScript + Lint + Test) (push) Has been cancelled

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-29 17:02:55 +08:00
parent 44cd6c6595
commit 5c73321ce6
3 changed files with 14 additions and 4 deletions
+6
View File
@@ -172,6 +172,7 @@ patheditor profile apply "Python开发"
## 功能 ## 功能
### 路径管理 ### 路径管理
- 查看和编辑 **系统 PATH**HKLM)和 **用户 PATH**HKCU - 查看和编辑 **系统 PATH**HKLM)和 **用户 PATH**HKCU
- 新建、编辑、删除、上移、下移路径条目 - 新建、编辑、删除、上移、下移路径条目
- 多选批量删除 - 多选批量删除
@@ -180,26 +181,31 @@ patheditor profile apply "Python开发"
- 文件夹拖拽添加 - 文件夹拖拽添加
### 路径验证 ### 路径验证
- **红色**标记:路径在文件系统中不存在 - **红色**标记:路径在文件系统中不存在
- **橙色**标记:路径在列表中重复出现 - **橙色**标记:路径在列表中重复出现
- 环境变量路径(含 `%VAR%`)悬浮展开预览 - 环境变量路径(含 `%VAR%`)悬浮展开预览
### 撤销/重做 ### 撤销/重做
- 支持 9 种操作类型,最多 50 步历史 - 支持 9 种操作类型,最多 50 步历史
- 新增、删除、编辑、移动、清理、清空、导入均可撤销 - 新增、删除、编辑、移动、清理、清空、导入均可撤销
### 导入/导出 ### 导入/导出
- **JSON**:结构化导出,含版本和时间戳 - **JSON**:结构化导出,含版本和时间戳
- **CSV**UTF-8 BOM 编码,兼容 Excel - **CSV**UTF-8 BOM 编码,兼容 Excel
- **TXT**:纯文本,每行一个路径 - **TXT**:纯文本,每行一个路径
### 安全 ### 安全
- 保存前自动备份注册表到 `%APPDATA%/PathEditor/backups/` - 保存前自动备份注册表到 `%APPDATA%/PathEditor/backups/`
- PATH 长度检查(Windows 单变量上限 32767 字符) - PATH 长度检查(Windows 单变量上限 32767 字符)
- 非管理员自动进入**只读模式** - 非管理员自动进入**只读模式**
- 保存中途失败精确提示哪个注册表 hive 出错 - 保存中途失败精确提示哪个注册表 hive 出错
### 界面 ### 界面
- 深色模式 / 浅色模式 - 深色模式 / 浅色模式
- 中文 / English 界面切换 - 中文 / English 界面切换
- 全局键盘快捷键 - 全局键盘快捷键
+4 -2
View File
@@ -1,4 +1,4 @@
import { useState, useEffect, useMemo } from 'react'; import { useState, useEffect, useMemo, useRef } from 'react';
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Modal } from '@/components/ui/Modal'; import { Modal } from '@/components/ui/Modal';
@@ -35,8 +35,10 @@ export function AnalyzeDialog({ open, onClose }: Props) {
const [toolGroups, setToolGroups] = useState<ToolGroup[]>([]); const [toolGroups, setToolGroups] = useState<ToolGroup[]>([]);
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const prevOpen = useRef(false);
useEffect(() => { useEffect(() => {
if (!open) return; if (!open || prevOpen.current) return;
prevOpen.current = open;
setLoading(true); setLoading(true);
const paths = getEnabledPaths(); const paths = getEnabledPaths();
Promise.all([ Promise.all([
+4 -2
View File
@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback, useRef } from 'react';
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Modal } from '@/components/ui/Modal'; import { Modal } from '@/components/ui/Modal';
@@ -39,8 +39,10 @@ export function ProfileDialog({ open, onClose }: Props) {
setProfiles(list); setProfiles(list);
}, []); }, []);
const prevOpen = useRef(false);
useEffect(() => { useEffect(() => {
if (open) refreshProfiles(); if (open && !prevOpen.current) refreshProfiles();
prevOpen.current = open;
}, [open, refreshProfiles]); }, [open, refreshProfiles]);
const handleSave = async () => { const handleSave = async () => {