Skip to content

Commit 464630d

Browse files
🐛 fix(webview-ui): resolve react-hooks lint errors in settings flows
1 parent f528b58 commit 464630d

File tree

4 files changed

+35
-24
lines changed

4 files changed

+35
-24
lines changed

webview-ui/src/components/prompts/storage-level-modal.tsx

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ export const StorageLevelModal: React.FC<StorageLevelModalProps> = ({
2525
string | undefined
2626
>();
2727

28+
const handleClose = React.useCallback(() => {
29+
setSelectedLevel("global");
30+
setSelectedWorkspace(undefined);
31+
onClose();
32+
}, [onClose]);
33+
2834
const handleConfirm = () => {
2935
if (
3036
(selectedLevel === "workspace" || selectedLevel === "project") &&
@@ -38,31 +44,23 @@ export const StorageLevelModal: React.FC<StorageLevelModalProps> = ({
3844
selectedWorkspace,
3945
);
4046
onSelect(selectedLevel, selectedWorkspace);
41-
onClose();
47+
handleClose();
4248
};
4349

44-
// 重置状态当模态框关闭时
45-
React.useEffect(() => {
46-
if (!isOpen) {
47-
setSelectedLevel("global");
48-
setSelectedWorkspace(undefined);
49-
}
50-
}, [isOpen]);
51-
5250
if (!isOpen) return null;
5351

5452
return (
5553
<div
5654
className="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
5755
onClick={(e) => {
5856
if (e.target === e.currentTarget) {
59-
onClose();
57+
handleClose();
6058
}
6159
}}
6260
>
6361
<div className="bg-[var(--vscode-editor-background)] border border-[var(--vscode-widget-border)] rounded-lg p-6 max-w-md w-full mx-4 shadow-2xl relative">
6462
<button
65-
onClick={onClose}
63+
onClick={handleClose}
6664
className="absolute right-4 top-4 w-6 h-6 flex items-center justify-center rounded hover:bg-[var(--vscode-list-hoverBackground)] text-[var(--vscode-foreground)]"
6765
aria-label="Close dialog"
6866
>
@@ -209,7 +207,7 @@ export const StorageLevelModal: React.FC<StorageLevelModalProps> = ({
209207
{/* 按钮区域 */}
210208
<div className="flex justify-end space-x-2 mt-6">
211209
<button
212-
onClick={onClose}
210+
onClick={handleClose}
213211
className="px-4 py-2 rounded bg-[var(--vscode-button-secondary-background)] text-[var(--vscode-button-secondary-foreground)] hover:bg-[var(--vscode-button-secondary-hover-background)] border border-[var(--vscode-button-border)]"
214212
>
215213
{t("cancel")}

webview-ui/src/components/settings/KeyValueField.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,15 @@ export const KeyValueField: React.FC<KeyValueFieldProps> = ({
4040
value && typeof value === "object" && !Array.isArray(value)
4141
? Object.entries(value as Record<string, string>)
4242
: [];
43-
// Avoid unnecessary re-renders if the value hasn't changed
44-
if (JSON.stringify(newHeaders) !== JSON.stringify(localHeaders)) {
45-
setLocalHeaders(newHeaders);
46-
}
47-
}, [value, localHeaders]);
43+
// Avoid synchronous setState directly inside effects.
44+
queueMicrotask(() => {
45+
setLocalHeaders((prevHeaders) =>
46+
JSON.stringify(newHeaders) === JSON.stringify(prevHeaders)
47+
? prevHeaders
48+
: newHeaders,
49+
);
50+
});
51+
}, [value]);
4852

4953
const handleAddRow = () => {
5054
const newHeaders = [...localHeaders, ["", ""] as [string, string]];

webview-ui/src/contexts/SettingsContext.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export const SettingsProvider: React.FC<SettingsProviderProps> = ({
2323
const [hasUnsavedChanges, setHasUnsavedChanges] = useState<boolean>(false);
2424
const [isLoading, setIsLoading] = useState(true);
2525
const [error, setError] = useState<string | null>(null);
26+
const editingProfileId = editingProfile?.id ?? null;
2627

2728
const activeProfile =
2829
availableProfiles.find((p) => p.id === activeProfileId) || null;
@@ -45,7 +46,7 @@ export const SettingsProvider: React.FC<SettingsProviderProps> = ({
4546

4647
// 如果当前没有正在编辑的配置,或正在编辑的配置已被删除,则重置为新的活跃配置
4748
const editingProfileStillExists = data.profiles.some(
48-
(p) => p.id === editingProfile?.id,
49+
(p) => p.id === editingProfileId,
4950
);
5051

5152
if (!editingProfileStillExists) {
@@ -58,7 +59,7 @@ export const SettingsProvider: React.FC<SettingsProviderProps> = ({
5859
setHasUnsavedChanges(false);
5960
}
6061
},
61-
[editingProfile?.id],
62+
[editingProfileId],
6263
);
6364

6465
// 加载初始数据
@@ -84,7 +85,10 @@ export const SettingsProvider: React.FC<SettingsProviderProps> = ({
8485

8586
// 组件挂载时加载数据
8687
useEffect(() => {
87-
loadData();
88+
const timer = setTimeout(() => {
89+
void loadData();
90+
}, 0);
91+
return () => clearTimeout(timer);
8892
}, [loadData]);
8993

9094
// ==================== 操作方法 ====================
@@ -100,7 +104,7 @@ export const SettingsProvider: React.FC<SettingsProviderProps> = ({
100104
prev.map((p) => (p.id === profile.id ? { ...profile } : p)),
101105
);
102106

103-
if (profile.id === editingProfile?.id) {
107+
if (profile.id === editingProfileId) {
104108
setEditingProfileState({ ...profile });
105109
setHasUnsavedChanges(false);
106110
}
@@ -114,7 +118,7 @@ export const SettingsProvider: React.FC<SettingsProviderProps> = ({
114118
throw err;
115119
}
116120
},
117-
[editingProfile?.id],
121+
[editingProfileId],
118122
);
119123

120124
const activateProfile = useCallback(

webview-ui/src/pages/settings/SettingsPage.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,10 @@ export const SettingsPage: React.FC = () => {
106106
}, [t]);
107107

108108
useEffect(() => {
109-
loadData();
109+
const timer = setTimeout(() => {
110+
void loadData();
111+
}, 0);
112+
return () => clearTimeout(timer);
110113
}, [loadData]);
111114

112115
useEffect(() => {
@@ -118,7 +121,9 @@ export const SettingsPage: React.FC = () => {
118121
"advanced",
119122
]);
120123
if (tab && validTabs.has(tab)) {
121-
setSelectedTab(tab);
124+
queueMicrotask(() => {
125+
setSelectedTab((prevTab) => (prevTab === tab ? prevTab : tab));
126+
});
122127
}
123128
}, [location.search]);
124129

0 commit comments

Comments
 (0)