Skip to content

Commit abde56c

Browse files
committed
fix: list check logic
1 parent e226ffe commit abde56c

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

src/useForm.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,12 +784,13 @@ export class FormStore {
784784
const { onValuesChange } = this.callbacks;
785785

786786
if (onValuesChange) {
787+
const fieldEntity = this.getFieldsMap(true).get(namePath);
787788
const changedValues = cloneByNamePathList(this.store, [namePath]);
788789
const allValues = this.getFieldsValue();
789790
// Merge changedValues into allValues to ensure allValues contains the latest changes
790791
const mergedAllValues = mergeWith([allValues, changedValues], {
791792
// When value is array, it means trigger by Form.List which should replace directly
792-
prepareArray: current => (Array.isArray(value) ? [] : [...(current || [])]),
793+
prepareArray: current => (fieldEntity?.isList() ? [] : [...(current || [])]),
793794
});
794795
onValuesChange(changedValues, mergedAllValues);
795796
}

tests/list.test.tsx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,4 +1075,68 @@ describe('Form.List', () => {
10751075
{ list: [{ first: 'light', last: 'little' }] },
10761076
);
10771077
});
1078+
1079+
it('should correctly merge array-valued fields within Form.List items without losing data', async () => {
1080+
const TagInput = ({ value = [], onChange }: any) => (
1081+
<input
1082+
data-testid="tag-input"
1083+
value={value.join(',')}
1084+
onChange={e => {
1085+
const newValue = e.target.value
1086+
.split(',')
1087+
.map(s => s.trim())
1088+
.filter(Boolean);
1089+
onChange(newValue);
1090+
}}
1091+
/>
1092+
);
1093+
1094+
const onValuesChange = jest.fn();
1095+
1096+
const [container] = generateForm(
1097+
fields => (
1098+
<>
1099+
{fields.map(field => (
1100+
<div key={field.key}>
1101+
<Field {...field} name={[field.name, 'name']}>
1102+
<Input />
1103+
</Field>
1104+
<Field {...field} name={[field.name, 'tags']}>
1105+
<TagInput />
1106+
</Field>
1107+
</div>
1108+
))}
1109+
</>
1110+
),
1111+
{
1112+
initialValues: {
1113+
list: [{ name: 'John', tags: ['react', 'js'] }],
1114+
},
1115+
onValuesChange,
1116+
},
1117+
);
1118+
1119+
const tagInput = container.querySelector('input[data-testid="tag-input"]') as HTMLElement;
1120+
1121+
await act(async () => {
1122+
fireEvent.change(tagInput, {
1123+
target: { value: 'react,ts' },
1124+
});
1125+
});
1126+
1127+
expect(onValuesChange).toHaveBeenCalledWith(
1128+
{ list: [{ tags: ['react', 'ts'] }] }, // changedValues
1129+
{ list: [{ name: 'John', tags: ['react', 'ts'] }] }, // allValues
1130+
);
1131+
onValuesChange.mockReset();
1132+
1133+
await act(async () => {
1134+
fireEvent.change(tagInput, { target: { value: 'react,ts,redux' } });
1135+
});
1136+
1137+
expect(onValuesChange).toHaveBeenLastCalledWith(
1138+
{ list: [{ tags: ['react', 'ts', 'redux'] }] },
1139+
{ list: [{ name: 'John', tags: ['react', 'ts', 'redux'] }] },
1140+
);
1141+
});
10781142
});

0 commit comments

Comments
 (0)