-
-
Notifications
You must be signed in to change notification settings - Fork 2k
/
useForm.ts
111 lines (99 loc) · 3.12 KB
/
useForm.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import React from 'react';
import { createFormControl } from './logic/createFormControl';
import getProxyFormState from './logic/getProxyFormState';
import shouldRenderFormState from './logic/shouldRenderFormState';
import { FieldValues, FormState, UseFormProps, UseFormReturn } from './types';
import { useSubscribe } from './useSubscribe';
/**
* Custom hook to manage the entire form.
*
* @remarks
* [API](https://react-hook-form.com/api/useform) • [Demo](https://codesandbox.io/s/react-hook-form-get-started-ts-5ksmm) • [Video](https://www.youtube.com/watch?v=RkXv4AXXC_4)
*
* @param props - form configuration and validation parameters.
*
* @returns methods - individual functions to manage the form state. {@link UseFormReturn}
*
* @example
* ```tsx
* function App() {
* const { register, handleSubmit, watch, formState: { errors } } = useForm();
* const onSubmit = data => console.log(data);
*
* console.log(watch("example"));
*
* return (
* <form onSubmit={handleSubmit(onSubmit)}>
* <input defaultValue="test" {...register("example")} />
* <input {...register("exampleRequired", { required: true })} />
* {errors.exampleRequired && <span>This field is required</span>}
* <input type="submit" />
* </form>
* );
* }
* ```
*/
export function useForm<
TFieldValues extends FieldValues = FieldValues,
TContext = any,
>(
props: UseFormProps<TFieldValues, TContext> = {},
): UseFormReturn<TFieldValues, TContext> {
const _formControl = React.useRef<
UseFormReturn<TFieldValues, TContext> | undefined
>();
const [formState, updateFormState] = React.useState<FormState<TFieldValues>>({
isDirty: false,
isValidating: false,
isSubmitted: false,
isSubmitting: false,
isSubmitSuccessful: false,
isValid: false,
submitCount: 0,
dirtyFields: {},
touchedFields: {},
errors: {},
defaultValues: props.defaultValues,
});
if (!_formControl.current) {
_formControl.current = {
...createFormControl(props, () =>
updateFormState((formState) => ({ ...formState })),
),
formState,
};
}
const control = _formControl.current.control;
control._options = props;
useSubscribe({
subject: control._subjects.state,
callback: React.useCallback(
(value: FieldValues) => {
if (shouldRenderFormState(value, control._proxyFormState, true)) {
control._formState = {
...control._formState,
...value,
};
updateFormState({ ...control._formState });
}
},
[control],
),
});
React.useEffect(() => {
if (!control._stateFlags.mount) {
control._proxyFormState.isValid && control._updateValid();
control._stateFlags.mount = true;
}
if (control._stateFlags.watch) {
control._stateFlags.watch = false;
control._subjects.state.next({});
}
control._removeUnmounted();
});
React.useEffect(() => {
formState.submitCount && control._focusError();
}, [control, formState.submitCount]);
_formControl.current.formState = getProxyFormState(formState, control);
return _formControl.current;
}