Skip to content

Commit 0a696bb

Browse files
committed
fix: use mountedFieldsRef
1 parent 554f4dc commit 0a696bb

6 files changed

Lines changed: 40 additions & 15 deletions

File tree

packages/components/form/Form.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ const Form = forwardRefWithStatics(
5555
const formRef = useRef<HTMLFormElement>(null);
5656
const formMapRef = useRef(new Map()); // 收集所有包含 name 属性 formItem 实例
5757
const floatingFormDataRef = useRef({}); // 储存游离值的 formData
58+
const mountedFieldsRef = useRef<Set<string>>(new Set()); // Form 生命周期内所有曾经被 FormItem 挂载过的字段(fullPath 序列化后的字符串)
59+
5860
const formInstance = useInstance(props, formRef, formMapRef, floatingFormDataRef, form);
5961

6062
useImperativeHandle(ref, () => formInstance);
@@ -81,6 +83,7 @@ const Form = forwardRefWithStatics(
8183
form?.getInternalHooks?.(HOOK_MARK)?.notifyWatch?.([]);
8284
form.store = {};
8385
floatingFormDataRef.current = {};
86+
mountedFieldsRef.current.clear();
8487
onReset?.({ e });
8588
}
8689

@@ -115,6 +118,7 @@ const Form = forwardRefWithStatics(
115118
readOnly: props.readOnly || props.readonly,
116119
formMapRef,
117120
floatingFormDataRef,
121+
mountedFieldsRef,
118122
onFormItemValueChange,
119123
}}
120124
>

packages/components/form/FormContext.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const FormContext = React.createContext<{
2323
errorMessage: TdFormProps['errorMessage'];
2424
formMapRef: React.RefObject<Map<any, React.RefObject<FormItemInstance>>>;
2525
floatingFormDataRef: React.RefObject<Record<any, any>>;
26+
mountedFieldsRef?: React.RefObject<Set<string>>;
2627
onFormItemValueChange: (changedValue: Record<string, unknown>) => void;
2728
}>({
2829
form: undefined,
@@ -44,6 +45,7 @@ const FormContext = React.createContext<{
4445
onFormItemValueChange: undefined,
4546
formMapRef: undefined,
4647
floatingFormDataRef: undefined,
48+
mountedFieldsRef: undefined,
4749
});
4850

4951
export const useFormContext = () => React.useContext(FormContext);

packages/components/form/FormItem.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const FormItem = forwardRef<FormItemInstance, FormItemProps>((originalProps, ref
7979
statusIcon: statusIconFromContext,
8080
errorMessage,
8181
formMapRef,
82+
mountedFieldsRef,
8283
onFormItemValueChange,
8384
} = useFormContext();
8485

@@ -435,15 +436,25 @@ const FormItem = forwardRef<FormItemInstance, FormItemProps>((originalProps, ref
435436
shouldValidate.current = false;
436437
shouldEmitChangeRef.current = false;
437438

438-
// remount 场景
439-
// 若 store 中已存在有效值,复用它并同步到本地 state
440-
// 避免被 initialData / children 默认值抹回
441-
const existingStoreValue = has(form?.store, fullPath) ? get(form?.store, fullPath) : undefined;
442-
if (typeof existingStoreValue !== 'undefined') {
443-
setFormValue(existingStoreValue);
439+
// 区分「首次挂载」与「remount 到已有 form」:
440+
// - 首次挂载:mountedFieldsRef 中不含该 fullPath → 用 initialData 初始化 store
441+
// - remount:mountedFieldsRef 中已含该 fullPath → 保留 store 现值(可能是用户输入 / setFieldsValue 写入),
442+
// 避免 Dialog / Popup 等场景下条件渲染引发 FormItem 卸载 → 重挂载时把已修改的字段恢复成 initialData
443+
// FormItem 卸载不从 mountedFieldsRef 中移除,只有 Form 整体 reset 时才清空
444+
const fieldKey = JSON.stringify(fullPath);
445+
const isRemount = mountedFieldsRef?.current?.has(fieldKey) ?? false;
446+
if (isRemount) {
447+
const existingStoreValue = has(form?.store, fullPath) ? get(form?.store, fullPath) : undefined;
448+
if (typeof existingStoreValue !== 'undefined') {
449+
setFormValue(existingStoreValue);
450+
} else {
451+
set(form?.store, fullPath, defaultInitialData);
452+
setFormValue(defaultInitialData);
453+
}
444454
} else {
445455
set(form?.store, fullPath, defaultInitialData);
446456
setFormValue(defaultInitialData);
457+
mountedFieldsRef?.current?.add(fieldKey);
447458
}
448459

449460
return () => {

packages/components/form/_example/validate-complicated-data.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ export default function BaseForm() {
121121
theme="card"
122122
addable
123123
onAdd={onAddStudent}
124-
style={{ marginLeft: 30, border: '1px solid var(--td-component-stroke)' }}
124+
style={{
125+
marginLeft: 30,
126+
border: '1px solid var(--td-component-stroke)',
127+
}}
125128
>
126129
{formData.students.map((student, index) => (
127130
<Tabs.TabPanel key={student.id} value={student.id} label={student.label} destroyOnHide={false}>
@@ -130,14 +133,19 @@ export default function BaseForm() {
130133
<Input placeholder="请输入内容" />
131134
</FormItem>
132135

133-
<FormItem label="选科" name={`students[${index}].name`} label-width={80} initialData={student.courseType}>
136+
<FormItem
137+
label="选科"
138+
name={`students[${index}].courseType`}
139+
label-width={80}
140+
initialData={student.courseType}
141+
>
134142
<Radio.Group>
135143
<Radio value="wenke">文科</Radio>
136144
<Radio value="like">理科</Radio>
137145
</Radio.Group>
138146
</FormItem>
139147

140-
<FormItem label="课程" name={`students[${index}].name`} label-width={80} initialData={student.course}>
148+
<FormItem label="课程" name={`students[${index}].course`} label-width={80} initialData={student.course}>
141149
<Checkbox.Group>
142150
{courseOptions.map(({ value, label }, index) => (
143151
<Checkbox key={index} value={value} label={label} />

test/snap/__snapshots__/csr.test.jsx.snap

Lines changed: 5 additions & 5 deletions
Large diffs are not rendered by default.

test/snap/__snapshots__/ssr.test.jsx.snap

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)