diff --git a/src/hooks/useForm.ts b/src/hooks/useForm.ts index 3353d8e61..12f99f9d7 100644 --- a/src/hooks/useForm.ts +++ b/src/hooks/useForm.ts @@ -239,6 +239,11 @@ export class FormStore { return this.fieldEntities.filter(field => field.getNamePath().length); }; + /** + * Get a map of registered field entities with their name path as the key. + * @param pure Only include fields which have a `name`. Default: false + * @returns A NameMap containing field entities indexed by their name paths + */ private getFieldsMap = (pure: boolean = false) => { const cache: NameMap = new NameMap(); this.getFieldEntities(pure).forEach(field => { @@ -248,14 +253,35 @@ export class FormStore { return cache; }; - private getFieldEntitiesForNamePathList = (nameList?: NamePath[]): FlexibleFieldEntity[] => { + /** + * Get field entities based on a list of name paths. + * @param nameList - Array of name paths to search for. If not provided, returns all field entities with names. + * @param includesSubNamePath - Whether to include fields that have the given name path as a prefix. + */ + private getFieldEntitiesForNamePathList = ( + nameList?: NamePath[], + includesSubNamePath = false, + ): FlexibleFieldEntity[] => { if (!nameList) { return this.getFieldEntities(true); } const cache = this.getFieldsMap(true); - return nameList.map(name => { + + if (!includesSubNamePath) { + return nameList.map(name => { + const namePath = getNamePath(name); + return cache.get(namePath) || { INVALIDATE_NAME_PATH: getNamePath(name) }; + }); + } + + return nameList.flatMap(name => { const namePath = getNamePath(name); - return cache.get(namePath) || { INVALIDATE_NAME_PATH: getNamePath(name) }; + const fields: FlexibleFieldEntity[] = cache.getAsPrefix(namePath); + + if (fields.length) { + return fields; + } + return [{ INVALIDATE_NAME_PATH: namePath }]; }); }; @@ -282,6 +308,7 @@ export class FormStore { const fieldEntities = this.getFieldEntitiesForNamePathList( Array.isArray(mergedNameList) ? mergedNameList : null, + true, ); const filteredNameList: NamePath[] = []; diff --git a/src/utils/NameMap.ts b/src/utils/NameMap.ts index b4259dd46..84747acde 100644 --- a/src/utils/NameMap.ts +++ b/src/utils/NameMap.ts @@ -33,6 +33,25 @@ class NameMap { return this.kvs.get(normalize(key)); } + public getAsPrefix(key: InternalNamePath): T[] { + const normalizedKey = normalize(key); + const normalizedPrefix = normalizedKey + SPLIT; + const results: T[] = []; + + const current = this.kvs.get(normalizedKey); + if (current !== undefined) { + results.push(current); + } + + this.kvs.forEach((value, itemNormalizedKey) => { + if (itemNormalizedKey.startsWith(normalizedPrefix)) { + results.push(value); + } + }); + + return results; + } + public update(key: InternalNamePath, updater: (origin: T) => T | null) { const origin = this.get(key); const next = updater(origin); diff --git a/tests/list.test.tsx b/tests/list.test.tsx index 8c312d313..9aac91b39 100644 --- a/tests/list.test.tsx +++ b/tests/list.test.tsx @@ -1171,4 +1171,23 @@ describe('Form.List', () => { list: [{ name: 'A' }, { name: 'BB' }, { name: 'C' }, { name: 'D' }], }); }); + + it('getFieldsValue(["list"]) should same as getFieldsValue().list', async () => { + generateForm( + fields => + fields.map(field => ( + + + + )), + { + initialValues: { + list: [{ name: 'bamboo', notExist: 'little' }], + }, + }, + ); + + expect(form.current!.getFieldsValue()).toEqual({ list: [{ name: 'bamboo' }] }); + expect(form.current!.getFieldsValue(['list'])).toEqual({ list: [{ name: 'bamboo' }] }); + }); });