From 96bf86d69879441dd52bd153d0f605875fd84869 Mon Sep 17 00:00:00 2001 From: zhengjihao <2714499297@qq.com> Date: Sun, 3 May 2026 23:12:50 +0800 Subject: [PATCH] feat: add getFieldsName API to form instance --- docs/demo/getFieldsName.md | 3 + docs/examples/getFieldsName.tsx | 25 +++++++++ src/FieldContext.ts | 1 + src/hooks/useForm.ts | 6 ++ src/interface.ts | 1 + tests/getFieldsName.test.tsx | 98 +++++++++++++++++++++++++++++++++ 6 files changed, 134 insertions(+) create mode 100644 docs/demo/getFieldsName.md create mode 100644 docs/examples/getFieldsName.tsx create mode 100644 tests/getFieldsName.test.tsx diff --git a/docs/demo/getFieldsName.md b/docs/demo/getFieldsName.md new file mode 100644 index 000000000..919881dbf --- /dev/null +++ b/docs/demo/getFieldsName.md @@ -0,0 +1,3 @@ +## getFieldsName + + diff --git a/docs/examples/getFieldsName.tsx b/docs/examples/getFieldsName.tsx new file mode 100644 index 000000000..934242b44 --- /dev/null +++ b/docs/examples/getFieldsName.tsx @@ -0,0 +1,25 @@ +import Form, { Field } from 'rc-field-form'; +import React from 'react'; +import Input from './components/Input'; + +export default () => { + const [form] = Form.useForm(); + + return ( +
+ + + + + + + + {() => ( +
+            {JSON.stringify(form.getFieldsName(), null, 2)}
+          
+ )} +
+
+ ); +}; diff --git a/src/FieldContext.ts b/src/FieldContext.ts index d2b6f4d5d..123c86dc4 100644 --- a/src/FieldContext.ts +++ b/src/FieldContext.ts @@ -14,6 +14,7 @@ const Context = React.createContext({ getFieldsValue: warningFunc, getFieldError: warningFunc, getFieldWarning: warningFunc, + getFieldsName: warningFunc, getFieldsError: warningFunc, isFieldsTouched: warningFunc, isFieldTouched: warningFunc, diff --git a/src/hooks/useForm.ts b/src/hooks/useForm.ts index c660f9a23..42fa167da 100644 --- a/src/hooks/useForm.ts +++ b/src/hooks/useForm.ts @@ -87,6 +87,7 @@ export class FormStore { getFieldsValue: this.getFieldsValue, getFieldError: this.getFieldError, getFieldWarning: this.getFieldWarning, + getFieldsName: this.getFieldsName, getFieldsError: this.getFieldsError, isFieldsTouched: this.isFieldsTouched, isFieldTouched: this.isFieldTouched, @@ -345,6 +346,11 @@ export class FormStore { return mergedValues; }; + private getFieldsName = (): InternalNamePath[] => { + this.warningUnhooked(); + return this.getFieldEntities(true).map(entity => entity.getNamePath()); + }; + private getFieldValue = (name: NamePath) => { this.warningUnhooked(); diff --git a/src/interface.ts b/src/interface.ts index 1af70ea59..584e21f8d 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -272,6 +272,7 @@ export interface FormInstance { getFieldError: (name: NamePath) => string[]; getFieldsError: (nameList?: NamePath[]) => FieldError[]; getFieldWarning: (name: NamePath) => string[]; + getFieldsName: () => NamePath[]; isFieldsTouched: ((nameList?: NamePath[], allFieldsTouched?: boolean) => boolean) & ((allFieldsTouched?: boolean) => boolean); isFieldTouched: (name: NamePath) => boolean; diff --git a/tests/getFieldsName.test.tsx b/tests/getFieldsName.test.tsx new file mode 100644 index 000000000..fdbfb7059 --- /dev/null +++ b/tests/getFieldsName.test.tsx @@ -0,0 +1,98 @@ +import { render } from '@testing-library/react'; +import React from 'react'; +import Form, { Field, List } from '../src'; +import type { FormInstance } from '../src'; +import { Input } from './common/InfoField'; + +describe('getFieldsName', () => { + it('returns empty array when no named fields', () => { + const formRef = React.createRef(); + render(
); + expect(formRef.current!.getFieldsName()).toEqual([]); + }); + + it('returns name paths of registered fields', () => { + const formRef = React.createRef(); + render( + + + + + + + + , + ); + expect(formRef.current!.getFieldsName()).toEqual([['username'], ['profile', 'email']]); + }); + + it('excludes field without name', () => { + const formRef = React.createRef(); + render( +
+ + + + {() => null} +
, + ); + expect(formRef.current!.getFieldsName()).toEqual([['a']]); + }); + + it('includes one entry per Field with the same name', () => { + const formRef = React.createRef(); + render( +
+ + + + + + +
, + ); + expect(formRef.current!.getFieldsName()).toEqual([['x'], ['x']]); + }); + + it('updates when field unmounts', () => { + const formRef = React.createRef(); + const Demo = ({ show }: { show: boolean }) => ( +
+ + + + {show ? ( + + + + ) : null} +
+ ); + const { rerender } = render(); + expect(formRef.current!.getFieldsName()).toEqual([['keep'], ['toggle']]); + rerender(); + expect(formRef.current!.getFieldsName()).toEqual([['keep']]); + }); + + it('includes Form.List item fields', () => { + const formRef = React.createRef(); + render( +
+ + {fields => + fields.map(f => ( + + + + )) + } + +
, + ); + expect(formRef.current!.getFieldsName()).toEqual([ + ['list', 0], + ['list', 1], + ['list'], + ]); + }); +});