From f12ffeabf41345333fe1e1b61acd2c8a8b147132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E8=89=B3=E5=85=B5?= Date: Tue, 16 Dec 2025 18:23:31 +0800 Subject: [PATCH 1/3] fix: getFieldsValue should return list root value when Form.List isn't wrapped --- src/useForm.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/useForm.ts b/src/useForm.ts index e2cd4b70b..54e482f81 100644 --- a/src/useForm.ts +++ b/src/useForm.ts @@ -346,8 +346,17 @@ export class FormStore { // We need fill the list as [] if Form.List is empty listNamePaths.forEach(namePath => { - if (!getValue(mergedValues, namePath)) { - mergedValues = setValue(mergedValues, namePath, []); + const listValue = getValue(mergedValues, namePath); + + // NOTE: `getFieldsValue(['list'])` may not include list root when Form.List isn't wrapped by a parent Field. + // In this case we should fallback to store value first, and only fill `[]` when store doesn't have it. + if (listValue === undefined) { + const storeListValue = getValue(this.store, namePath); + mergedValues = setValue( + mergedValues, + namePath, + storeListValue === undefined ? [] : storeListValue, + ); } }); From 90336e1a484f7d0b8deae9c251e3c089a3984d79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E8=89=B3=E5=85=B5?= Date: Tue, 16 Dec 2025 18:54:36 +0800 Subject: [PATCH 2/3] test: cover getFieldsValue with Form.List without parent Field --- tests/list.test.tsx | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/list.test.tsx b/tests/list.test.tsx index 8a207e240..7491126c0 100644 --- a/tests/list.test.tsx +++ b/tests/list.test.tsx @@ -1139,4 +1139,39 @@ describe('Form.List', () => { { list: [{ name: 'John', tags: ['react', 'ts', 'redux'] }] }, ); }); + + it('getFieldsValue should return list root value when Form.List is not wrapped by parent Field', async () => { + let operation: ListOperations; + + const [container] = generateForm((fields, opt) => { + operation = opt; + return ( +
+ {fields.map(field => ( +
+ + + + + + +
+ ))} +
+ ); + }); + + // First add a row + act(() => { + operation.add(); + }); + + // Fill some values + await changeValue(getInput(container, 0), 'n1'); // list[0].name + await changeValue(getInput(container, 1), '1'); // list[0].value + + expect(form.current?.getFieldsValue(['list'])).toEqual({ + list: [{ name: 'n1', value: '1' }], + }); + }); }); From fce8ad7c22fb798e7b3bc1f830e30cb6cf49833e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E8=89=B3=E5=85=B5?= Date: Fri, 19 Dec 2025 00:14:49 +0800 Subject: [PATCH 3/3] fix: align Form.List root value with store in getFieldsValue --- src/useForm.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/useForm.ts b/src/useForm.ts index 54e482f81..ce08d5bd8 100644 --- a/src/useForm.ts +++ b/src/useForm.ts @@ -346,17 +346,16 @@ export class FormStore { // We need fill the list as [] if Form.List is empty listNamePaths.forEach(namePath => { - const listValue = getValue(mergedValues, namePath); - - // NOTE: `getFieldsValue(['list'])` may not include list root when Form.List isn't wrapped by a parent Field. - // In this case we should fallback to store value first, and only fill `[]` when store doesn't have it. - if (listValue === undefined) { - const storeListValue = getValue(this.store, namePath); - mergedValues = setValue( - mergedValues, - namePath, - storeListValue === undefined ? [] : storeListValue, - ); + // Form.List 的数组结构(add/remove)会先同步更新 store, + // 而对应的子 Field 要到下一次 commit 才会 register。 + // 在这段 render 时序中,fieldEntities 仍然是“上一帧”的结果, + // 用它来拼 list 会得到不完整的数据。 + // 因此 List 根节点的值始终以 store 为准,避免依赖 Field 注册时序。 + const storeListValue = getValue(this.store, namePath); + + if (storeListValue !== undefined) { + mergedValues = setValue(mergedValues, namePath, storeListValue); + return; } });