From 0136afb6309dcb096043e3f8277dd524b4aa4733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E8=89=B3=E5=85=B5?= Date: Wed, 17 Dec 2025 10:05:10 +0800 Subject: [PATCH 1/2] fix(Form): avoid merging sparse list patches into allValue --- src/useForm.ts | 8 ++++---- tests/list.test.tsx | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/useForm.ts b/src/useForm.ts index e2cd4b70b..2fa75a951 100644 --- a/src/useForm.ts +++ b/src/useForm.ts @@ -788,10 +788,10 @@ export class FormStore { const changedValues = cloneByNamePathList(this.store, [namePath]); const allValues = this.getFieldsValue(); // Merge changedValues into allValues to ensure allValues contains the latest changes - const mergedAllValues = mergeWith([allValues, changedValues], { - // When value is array, it means trigger by Form.List which should replace directly - prepareArray: current => (fieldEntity?.isList() ? [] : [...(current || [])]), - }); + let mergedAllValues = allValues; + if (fieldEntity?.isList()) { + mergedAllValues = mergeWith([allValues, changedValues]); + } onValuesChange(changedValues, mergedAllValues); } diff --git a/tests/list.test.tsx b/tests/list.test.tsx index 8a207e240..8c312d313 100644 --- a/tests/list.test.tsx +++ b/tests/list.test.tsx @@ -1139,4 +1139,36 @@ describe('Form.List', () => { { list: [{ name: 'John', tags: ['react', 'ts', 'redux'] }] }, ); }); + + it('should not drop list items when updating list item field', async () => { + const onValuesChange = jest.fn(); + + const { getAllByRole } = render( +
+ + {fields => + fields.map(field => ( + + + + )) + } + +
, + ); + + // Change second item (index = 1) + fireEvent.change(getAllByRole('textbox')[1], { + target: { value: 'BB' }, + }); + + const [, allValues] = onValuesChange.mock.calls.pop(); + + expect(allValues).toEqual({ + list: [{ name: 'A' }, { name: 'BB' }, { name: 'C' }, { name: 'D' }], + }); + }); }); From cd345f31c729fb941a8911c6b9f73318c2fad008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E8=89=B3=E5=85=B5?= Date: Mon, 22 Dec 2025 18:09:46 +0800 Subject: [PATCH 2/2] revert: drop mergeWith changes in useForm (not root cause) --- src/useForm.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/useForm.ts b/src/useForm.ts index 2fa75a951..e2cd4b70b 100644 --- a/src/useForm.ts +++ b/src/useForm.ts @@ -788,10 +788,10 @@ export class FormStore { const changedValues = cloneByNamePathList(this.store, [namePath]); const allValues = this.getFieldsValue(); // Merge changedValues into allValues to ensure allValues contains the latest changes - let mergedAllValues = allValues; - if (fieldEntity?.isList()) { - mergedAllValues = mergeWith([allValues, changedValues]); - } + const mergedAllValues = mergeWith([allValues, changedValues], { + // When value is array, it means trigger by Form.List which should replace directly + prepareArray: current => (fieldEntity?.isList() ? [] : [...(current || [])]), + }); onValuesChange(changedValues, mergedAllValues); }