Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions src/hooks/useForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<FieldEntity> = new NameMap();
this.getFieldEntities(pure).forEach(field => {
Expand All @@ -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 }];
});
};

Expand All @@ -282,6 +308,7 @@ export class FormStore {

const fieldEntities = this.getFieldEntitiesForNamePathList(
Array.isArray(mergedNameList) ? mergedNameList : null,
true,
);

const filteredNameList: NamePath[] = [];
Expand Down
19 changes: 19 additions & 0 deletions src/utils/NameMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,25 @@ class NameMap<T> {
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);
Expand Down
19 changes: 19 additions & 0 deletions tests/list.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 => (
<Field {...fields} name={[field.name, 'name']} key={field.key}>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There appears to be a typo in this line. You are spreading fields (the array of ListField objects) as props to the Field component, instead of field (the individual ListField object from the map iteration). While the test might still pass because name and key are explicitly provided, spreading the fields array is incorrect and could pass unexpected props to the Field component.

Suggested change
<Field {...fields} name={[field.name, 'name']} key={field.key}>
<Field {...field} name={[field.name, 'name']} key={field.key}>

<Input />
</Field>
)),
{
initialValues: {
list: [{ name: 'bamboo', notExist: 'little' }],
},
},
);

expect(form.current!.getFieldsValue()).toEqual({ list: [{ name: 'bamboo' }] });
expect(form.current!.getFieldsValue(['list'])).toEqual({ list: [{ name: 'bamboo' }] });
});
});