Skip to content

Commit 7544e70

Browse files
committed
fix: infinite re-render loop in DynamicFormComponent
The useEffect depended on onSubmit which was a new closure every parent render. Calling onSubmit inside the effect triggered parent state update → re-render → new onSubmit ref → effect re-runs → loop. Fix: use useRef to hold a stable reference to onSubmit, removing it from the useEffect dependency array. Also add DialogDescription to BotDetailDialog to suppress Radix aria-describedby warning.
1 parent 526ddcd commit 7544e70

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

web/src/app/home/bots/BotDetailDialog.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
Dialog,
66
DialogContent,
77
DialogHeader,
8+
DialogDescription,
89
DialogTitle,
910
DialogFooter,
1011
} from '@/components/ui/dialog';
@@ -136,6 +137,7 @@ export default function BotDetailDialog({
136137
<main className="flex flex-1 flex-col h-[70vh]">
137138
<DialogHeader className="px-6 pt-6 pb-4 shrink-0">
138139
<DialogTitle>{t('bots.createBot')}</DialogTitle>
140+
<DialogDescription className="sr-only">{t('bots.createBot')}</DialogDescription>
139141
</DialogHeader>
140142
<div className="flex-1 overflow-y-auto px-6 pb-6">
141143
<BotForm
@@ -207,6 +209,13 @@ export default function BotDetailDialog({
207209
? t('bots.botLogTitle')
208210
: t('bots.sessionMonitor.title')}
209211
</DialogTitle>
212+
<DialogDescription className="sr-only">
213+
{activeMenu === 'config'
214+
? t('bots.editBot')
215+
: activeMenu === 'logs'
216+
? t('bots.botLogTitle')
217+
: t('bots.sessionMonitor.title')}
218+
</DialogDescription>
210219
</DialogHeader>
211220
<div className={activeMenu === 'sessions' ? 'flex-1 min-h-0' : 'flex-1 overflow-y-auto px-6 pb-6'}>
212221
{activeMenu === 'config' && (
@@ -257,6 +266,7 @@ export default function BotDetailDialog({
257266
<DialogContent>
258267
<DialogHeader>
259268
<DialogTitle>{t('common.confirmDelete')}</DialogTitle>
269+
<DialogDescription className="sr-only">{t('bots.deleteConfirmation')}</DialogDescription>
260270
</DialogHeader>
261271
<div className="py-4">{t('bots.deleteConfirmation')}</div>
262272
<DialogFooter>

web/src/app/home/components/dynamic-form/DynamicFormComponent.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ export default function DynamicFormComponent({
141141
}
142142
}, [initialValues, form, itemConfigList]);
143143

144+
// Stable ref for onSubmit to avoid re-triggering the effect when the
145+
// parent passes a new closure on every render.
146+
const onSubmitRef = useRef(onSubmit);
147+
onSubmitRef.current = onSubmit;
148+
144149
// 监听表单值变化
145150
useEffect(() => {
146151
// Emit initial form values immediately so the parent always has a valid snapshot,
@@ -154,7 +159,7 @@ export default function DynamicFormComponent({
154159
},
155160
{} as Record<string, object>,
156161
);
157-
onSubmit?.(initialFinalValues);
162+
onSubmitRef.current?.(initialFinalValues);
158163

159164
const subscription = form.watch(() => {
160165
const formValues = form.getValues();
@@ -165,10 +170,10 @@ export default function DynamicFormComponent({
165170
},
166171
{} as Record<string, object>,
167172
);
168-
onSubmit?.(finalValues);
173+
onSubmitRef.current?.(finalValues);
169174
});
170175
return () => subscription.unsubscribe();
171-
}, [form, onSubmit, itemConfigList]);
176+
}, [form, itemConfigList]);
172177

173178
return (
174179
<Form {...form}>

0 commit comments

Comments
 (0)