Skip to content

Commit 80eef50

Browse files
authored
feat: ref adding nativeElement (#691)
* feat: ref adding nativeForm * feat: add type test * feat: optimized code * feat: optimized code * fix: update ptimized code * feat: update * feat: update * feat: update
1 parent fcc2e64 commit 80eef50

File tree

4 files changed

+32
-23
lines changed

4 files changed

+32
-23
lines changed

src/Form.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
ValidateMessages,
77
Callbacks,
88
InternalFormInstance,
9+
FormRef,
910
} from './interface';
1011
import useForm from './useForm';
1112
import FieldContext, { HOOK_MARK } from './FieldContext';
@@ -36,7 +37,7 @@ export interface FormProps<Values = any> extends BaseFormProps {
3637
clearOnDestroy?: boolean;
3738
}
3839

39-
const Form: React.ForwardRefRenderFunction<FormInstance, FormProps> = (
40+
const Form: React.ForwardRefRenderFunction<FormRef, FormProps> = (
4041
{
4142
name,
4243
initialValues,
@@ -56,6 +57,7 @@ const Form: React.ForwardRefRenderFunction<FormInstance, FormProps> = (
5657
}: FormProps,
5758
ref,
5859
) => {
60+
const nativeElementRef = React.useRef<HTMLFormElement>(null);
5961
const formContext: FormContextProps = React.useContext(FormContext);
6062

6163
// We customize handle event since Context will makes all the consumer re-render:
@@ -71,7 +73,10 @@ const Form: React.ForwardRefRenderFunction<FormInstance, FormProps> = (
7173
} = (formInstance as InternalFormInstance).getInternalHooks(HOOK_MARK);
7274

7375
// Pass ref with form instance
74-
React.useImperativeHandle(ref, () => formInstance);
76+
React.useImperativeHandle(ref, () => ({
77+
...formInstance,
78+
nativeElement: nativeElementRef.current,
79+
}));
7580

7681
// Register form into Context
7782
React.useEffect(() => {
@@ -162,6 +167,7 @@ const Form: React.ForwardRefRenderFunction<FormInstance, FormProps> = (
162167
return (
163168
<Component
164169
{...restProps}
170+
ref={nativeElementRef}
165171
onSubmit={(event: React.FormEvent<HTMLFormElement>) => {
166172
event.preventDefault();
167173
event.stopPropagation();

src/index.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from 'react';
2-
import { FormInstance } from './interface';
2+
import type { FormRef, FormInstance } from './interface';
33
import Field from './Field';
44
import List from './List';
55
import useForm from './useForm';
@@ -10,8 +10,8 @@ import FieldContext from './FieldContext';
1010
import ListContext from './ListContext';
1111
import useWatch from './useWatch';
1212

13-
const InternalForm = React.forwardRef<FormInstance, FormProps>(FieldForm) as <Values = any>(
14-
props: FormProps<Values> & { ref?: React.Ref<FormInstance<Values>> },
13+
const InternalForm = React.forwardRef<FormRef, FormProps>(FieldForm) as <Values = any>(
14+
props: FormProps<Values> & { ref?: React.Ref<FormRef<Values>> },
1515
) => React.ReactElement;
1616

1717
type InternalFormType = typeof InternalForm;
@@ -33,6 +33,6 @@ RefForm.useWatch = useWatch;
3333

3434
export { Field, List, useForm, FormProvider, FieldContext, ListContext, useWatch };
3535

36-
export type { FormProps, FormInstance };
36+
export type { FormProps, FormInstance, FormRef };
3737

3838
export default RefForm;

src/interface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ export interface FormInstance<Values = any> {
273273
submit: () => void;
274274
}
275275

276+
export type FormRef<Values = any> = FormInstance<Values> & { nativeElement?: HTMLElement };
277+
276278
export type InternalFormInstance = Omit<FormInstance, 'validateFields'> & {
277279
validateFields: InternalValidateFields;
278280

tests/index.test.tsx

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Form, { Field, useForm } from '../src';
66
import { changeValue, getInput, matchError } from './common';
77
import InfoField, { Input } from './common/InfoField';
88
import timeout from './common/timeout';
9-
import type { Meta } from '@/interface';
9+
import type { FormRef, Meta } from '@/interface';
1010

1111
describe('Form.Basic', () => {
1212
describe('create form', () => {
@@ -85,7 +85,7 @@ describe('Form.Basic', () => {
8585
});
8686

8787
it('fields touched', async () => {
88-
const form = React.createRef<FormInstance>();
88+
const form = React.createRef<FormRef>();
8989

9090
const { container } = render(
9191
<div>
@@ -111,12 +111,15 @@ describe('Form.Basic', () => {
111111
expect(form.current?.isFieldsTouched(['username', 'password'])).toBeTruthy();
112112
expect(form.current?.isFieldsTouched(true)).toBeTruthy();
113113
expect(form.current?.isFieldsTouched(['username', 'password'], true)).toBeTruthy();
114+
115+
// nativeElementRef
116+
expect(form.current?.nativeElement).toBeTruthy();
114117
});
115118

116119
describe('reset form', () => {
117120
function resetTest(name: string, ...args) {
118121
it(name, async () => {
119-
const form = React.createRef<FormInstance>();
122+
const form = React.createRef<FormRef>();
120123
const onReset = jest.fn();
121124
const onMeta = jest.fn();
122125

@@ -187,7 +190,7 @@ describe('Form.Basic', () => {
187190
resetTest('without field name');
188191

189192
it('not affect others', async () => {
190-
const form = React.createRef<FormInstance>();
193+
const form = React.createRef<FormRef>();
191194

192195
const { container } = render(
193196
<div>
@@ -345,7 +348,7 @@ describe('Form.Basic', () => {
345348
it('getInternalHooks should not usable by user', () => {
346349
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
347350

348-
const form = React.createRef<FormInstance>();
351+
const form = React.createRef<FormRef>();
349352
render(
350353
<div>
351354
<Form ref={form} />
@@ -362,7 +365,7 @@ describe('Form.Basic', () => {
362365
});
363366

364367
it('valuePropName', async () => {
365-
const form = React.createRef<FormInstance>();
368+
const form = React.createRef<FormRef>();
366369
const { container } = render(
367370
<div>
368371
<Form ref={form}>
@@ -422,9 +425,7 @@ describe('Form.Basic', () => {
422425
<Field getValueProps={getValueProps1}>
423426
<span className="anything" />
424427
</Field>
425-
<Field getValueProps={getValueProps2}>
426-
{() => <span className="anything" />}
427-
</Field>
428+
<Field getValueProps={getValueProps2}>{() => <span className="anything" />}</Field>
428429
</Form>
429430
</div>,
430431
);
@@ -511,7 +512,7 @@ describe('Form.Basic', () => {
511512

512513
describe('setFields', () => {
513514
it('should work', () => {
514-
const form = React.createRef<FormInstance>();
515+
const form = React.createRef<FormRef>();
515516
const { container } = render(
516517
<div>
517518
<Form ref={form}>
@@ -535,7 +536,7 @@ describe('Form.Basic', () => {
535536

536537
it('should trigger by setField', () => {
537538
const triggerUpdate = jest.fn();
538-
const formRef = React.createRef<FormInstance>();
539+
const formRef = React.createRef<FormRef>();
539540

540541
render(
541542
<div>
@@ -596,7 +597,7 @@ describe('Form.Basic', () => {
596597
});
597598

598599
it('setFieldsValue should clean up status', async () => {
599-
const form = React.createRef<FormInstance>();
600+
const form = React.createRef<FormRef>();
600601
let currentMeta: Meta = null;
601602

602603
const { container } = render(
@@ -690,7 +691,7 @@ describe('Form.Basic', () => {
690691
});
691692

692693
it('filtering fields by meta', async () => {
693-
const form = React.createRef<FormInstance>();
694+
const form = React.createRef<FormRef>();
694695

695696
const { container } = render(
696697
<div>
@@ -857,7 +858,7 @@ describe('Form.Basic', () => {
857858
});
858859

859860
it('setFieldValue', () => {
860-
const formRef = React.createRef<FormInstance>();
861+
const formRef = React.createRef<FormRef>();
861862

862863
const Demo: React.FC = () => (
863864
<Form ref={formRef} initialValues={{ list: ['bamboo', 'little', 'light'] }}>
@@ -894,7 +895,7 @@ describe('Form.Basic', () => {
894895

895896
it('onMetaChange should only trigger when meta changed', () => {
896897
const onMetaChange = jest.fn();
897-
const formRef = React.createRef<FormInstance>();
898+
const formRef = React.createRef<FormRef>();
898899

899900
const Demo: React.FC = () => (
900901
<Form ref={formRef}>
@@ -920,7 +921,7 @@ describe('Form.Basic', () => {
920921
describe('set to null value', () => {
921922
function test(name: string, callback: (form: FormInstance) => void) {
922923
it(name, async () => {
923-
const form = React.createRef<FormInstance>();
924+
const form = React.createRef<FormRef>();
924925

925926
const { container } = render(
926927
<div>
@@ -953,7 +954,7 @@ describe('Form.Basic', () => {
953954

954955
it('setFieldValue should always set touched', async () => {
955956
const EMPTY_VALUES = { light: '', bamboo: [] };
956-
const formRef = React.createRef<FormInstance>();
957+
const formRef = React.createRef<FormRef>();
957958

958959
const Demo: React.FC = () => (
959960
<Form ref={formRef} initialValues={EMPTY_VALUES}>

0 commit comments

Comments
 (0)