react-hook-form 7.25.0 → 7.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -40,6 +40,7 @@ var get = (obj, path, defaultValue) => {
40
40
 
41
41
  const EVENTS = {
42
42
  BLUR: 'blur',
43
+ FOCUS_OUT: 'focusout',
43
44
  CHANGE: 'change',
44
45
  };
45
46
  const VALIDATION_MODE = {
@@ -66,26 +67,81 @@ var omit = (source, key) => {
66
67
  };
67
68
 
68
69
  const HookFormContext = React.createContext(null);
70
+ /**
71
+ * This custom hook allows you to access the form context. useFormContext is intended to be used in deeply nested structures, where it would become inconvenient to pass the context as a prop. To be used with {@link FormProvider}.
72
+ *
73
+ * @remarks
74
+ * [API](https://react-hook-form.com/api/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
75
+ *
76
+ * @returns return all useForm methods
77
+ *
78
+ * @example
79
+ * ```tsx
80
+ * function App() {
81
+ * const methods = useForm();
82
+ * const onSubmit = data => console.log(data);
83
+ *
84
+ * return (
85
+ * <FormProvider {...methods} >
86
+ * <form onSubmit={methods.handleSubmit(onSubmit)}>
87
+ * <NestedInput />
88
+ * <input type="submit" />
89
+ * </form>
90
+ * </FormProvider>
91
+ * );
92
+ * }
93
+ *
94
+ * function NestedInput() {
95
+ * const { register } = useFormContext(); // retrieve all hook methods
96
+ * return <input {...register("test")} />;
97
+ * }
98
+ * ```
99
+ */
69
100
  const useFormContext = () => React.useContext(HookFormContext);
101
+ /**
102
+ * A provider component that propagates the `useForm` methods to all children components via [React Context](https://reactjs.org/docs/context.html) API. To be used with {@link useFormContext}.
103
+ *
104
+ * @remarks
105
+ * [API](https://react-hook-form.com/api/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
106
+ *
107
+ * @param props - all useFrom methods
108
+ *
109
+ * @example
110
+ * ```tsx
111
+ * function App() {
112
+ * const methods = useForm();
113
+ * const onSubmit = data => console.log(data);
114
+ *
115
+ * return (
116
+ * <FormProvider {...methods} >
117
+ * <form onSubmit={methods.handleSubmit(onSubmit)}>
118
+ * <NestedInput />
119
+ * <input type="submit" />
120
+ * </form>
121
+ * </FormProvider>
122
+ * );
123
+ * }
124
+ *
125
+ * function NestedInput() {
126
+ * const { register } = useFormContext(); // retrieve all hook methods
127
+ * return <input {...register("test")} />;
128
+ * }
129
+ * ```
130
+ */
70
131
  const FormProvider = (props) => (React.createElement(HookFormContext.Provider, { value: omit(props, 'children') }, props.children));
71
132
 
72
133
  var getProxyFormState = (formState, _proxyFormState, localProxyFormState, isRoot = true) => {
73
- function createGetter(prop) {
74
- return () => {
75
- if (prop in formState) {
76
- if (_proxyFormState[prop] !== VALIDATION_MODE.all) {
77
- _proxyFormState[prop] = !isRoot || VALIDATION_MODE.all;
78
- }
79
- localProxyFormState && (localProxyFormState[prop] = true);
80
- return formState[prop];
81
- }
82
- return undefined;
83
- };
84
- }
85
134
  const result = {};
86
135
  for (const key in formState) {
87
136
  Object.defineProperty(result, key, {
88
- get: createGetter(key),
137
+ get: () => {
138
+ const _key = key;
139
+ if (_proxyFormState[_key] !== VALIDATION_MODE.all) {
140
+ _proxyFormState[_key] = !isRoot || VALIDATION_MODE.all;
141
+ }
142
+ localProxyFormState && (localProxyFormState[_key] = true);
143
+ return formState[_key];
144
+ },
89
145
  });
90
146
  }
91
147
  return result;
@@ -129,6 +185,36 @@ function useSubscribe(props) {
129
185
  }, [props.disabled]);
130
186
  }
131
187
 
188
+ /**
189
+ * This custom hook allows you to subscribe to each form state, and isolate the re-render at the custom hook level. It has its scope in terms of form state subscription, so it would not affect other useFormState and useForm. Using this hook can reduce the re-render impact on large and complex form application.
190
+ *
191
+ * @remarks
192
+ * [API](https://react-hook-form.com/api/useformstate) • [Demo](https://codesandbox.io/s/useformstate-75xly)
193
+ *
194
+ * @param props - include options on specify fields to subscribe. {@link UseFormStateReturn}
195
+ *
196
+ * @example
197
+ * ```tsx
198
+ * function App() {
199
+ * const { register, handleSubmit, control } = useForm({
200
+ * defaultValues: {
201
+ * firstName: "firstName"
202
+ * }});
203
+ * const { dirtyFields } = useFormState({
204
+ * control
205
+ * });
206
+ * const onSubmit = (data) => console.log(data);
207
+ *
208
+ * return (
209
+ * <form onSubmit={handleSubmit(onSubmit)}>
210
+ * <input {...register("firstName")} placeholder="First Name" />
211
+ * {dirtyFields.firstName && <p>Field is dirty.</p>}
212
+ * <input type="submit" />
213
+ * </form>
214
+ * );
215
+ * }
216
+ * ```
217
+ */
132
218
  function useFormState(props) {
133
219
  const methods = useFormContext();
134
220
  const { control = methods.control, disabled, name, exact } = props || {};
@@ -186,6 +272,22 @@ var objectHasFunction = (data) => {
186
272
  return false;
187
273
  };
188
274
 
275
+ /**
276
+ * Custom hook to subscribe to field change and isolate re-rendering at the component level.
277
+ *
278
+ * @remarks
279
+ *
280
+ * [API](https://react-hook-form.com/api/usewatch) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-usewatch-h9i5e)
281
+ *
282
+ * @example
283
+ * ```tsx
284
+ * const { watch } = useForm();
285
+ * const values = useWatch({
286
+ * name: "fieldName"
287
+ * control,
288
+ * })
289
+ * ```
290
+ */
189
291
  function useWatch(props) {
190
292
  const methods = useFormContext();
191
293
  const { control = methods.control, name, defaultValue, disabled, exact, } = props || {};
@@ -217,6 +319,30 @@ function useWatch(props) {
217
319
  return value;
218
320
  }
219
321
 
322
+ /**
323
+ * Custom hook to work with controlled component, this function provide you with both form and field level state. Re-render is isolated at the hook level.
324
+ *
325
+ * @remarks
326
+ * [API](https://react-hook-form.com/api/usecontroller) • [Demo](https://codesandbox.io/s/usecontroller-0o8px)
327
+ *
328
+ * @param props - the path name to the form field value, and validation rules.
329
+ *
330
+ * @returns field properties, field and form state. {@link UseControllerReturn}
331
+ *
332
+ * @example
333
+ * ```tsx
334
+ * function Input(props) {
335
+ * const { field, fieldState, formState } = useController(props);
336
+ * return (
337
+ * <div>
338
+ * <input {...field} placeholder={props.name} />
339
+ * <p>{fieldState.isTouched && "Touched"}</p>
340
+ * <p>{formState.isSubmitted ? "submitted" : ""}</p>
341
+ * </div>
342
+ * );
343
+ * }
344
+ * ```
345
+ */
220
346
  function useController(props) {
221
347
  const methods = useFormContext();
222
348
  const { name, control = methods.control, shouldUnregister } = props;
@@ -280,13 +406,55 @@ function useController(props) {
280
406
  reportValidity: () => elm.reportValidity(),
281
407
  };
282
408
  }
283
- }, [name, control]),
409
+ }, [name, control._fields]),
284
410
  },
285
411
  formState,
286
412
  fieldState: control.getFieldState(name, formState),
287
413
  };
288
414
  }
289
415
 
416
+ /**
417
+ * Component based on `useController` hook to work with controlled component.
418
+ *
419
+ * @remarks
420
+ * [API](https://react-hook-form.com/api/usecontroller/controller) • [Demo](https://codesandbox.io/s/react-hook-form-v6-controller-ts-jwyzw) • [Video](https://www.youtube.com/watch?v=N2UNk_UCVyA)
421
+ *
422
+ * @param props - the path name to the form field value, and validation rules.
423
+ *
424
+ * @returns provide field handler functions, field and form state.
425
+ *
426
+ * @example
427
+ * ```tsx
428
+ * function App() {
429
+ * const { control } = useForm<FormValues>({
430
+ * defaultValues: {
431
+ * test: ""
432
+ * }
433
+ * });
434
+ *
435
+ * return (
436
+ * <form>
437
+ * <Controller
438
+ * control={control}
439
+ * name="test"
440
+ * render={({ field: { onChange, onBlur, value, ref }, formState, fieldState }) => (
441
+ * <>
442
+ * <input
443
+ * onChange={onChange} // send value to hook form
444
+ * onBlur={onBlur} // notify when input is touched
445
+ * value={value} // return updated value
446
+ * ref={ref} // set ref for focus management
447
+ * />
448
+ * <p>{formState.isSubmitted ? "submitted" : ""}</p>
449
+ * <p>{fieldState.isTouched ? "touched" : ""}</p>
450
+ * </>
451
+ * )}
452
+ * />
453
+ * </form>
454
+ * );
455
+ * }
456
+ * ```
457
+ */
290
458
  const Controller = (props) => props.render(useController(props));
291
459
 
292
460
  var appendErrors = (name, validateAllFieldCriteria, errors, type, message) => validateAllFieldCriteria
@@ -436,7 +604,44 @@ var updateAt = (fieldValues, index, value) => {
436
604
  return fieldValues;
437
605
  };
438
606
 
439
- const useFieldArray = (props) => {
607
+ /**
608
+ * A custom hook that exposes convenient methods to perform operations with a list of dynamic inputs that need to be appended, updated, removed etc.
609
+ *
610
+ * @remarks
611
+ * [API](https://react-hook-form.com/api/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
612
+ *
613
+ * @param props - useFieldArray props
614
+ *
615
+ * @returns methods - functions to manipulate with the Field Arrays (dynamic inputs) {@link UseFieldArrayReturn}
616
+ *
617
+ * @example
618
+ * ```tsx
619
+ * function App() {
620
+ * const { register, control, handleSubmit, reset, trigger, setError } = useForm({
621
+ * defaultValues: {
622
+ * test: []
623
+ * }
624
+ * });
625
+ * const { fields, append } = useFieldArray({
626
+ * control,
627
+ * name: "test"
628
+ * });
629
+ *
630
+ * return (
631
+ * <form onSubmit={handleSubmit(data => console.log(data))}>
632
+ * {fields.map((item, index) => (
633
+ * <input key={item.id} {...register(`test.${index}.firstName`)} />
634
+ * ))}
635
+ * <button type="button" onClick={() => append({ firstName: "bill" })}>
636
+ * append
637
+ * </button>
638
+ * <input type="submit" />
639
+ * </form>
640
+ * );
641
+ * }
642
+ * ```
643
+ */
644
+ function useFieldArray(props) {
440
645
  const methods = useFormContext();
441
646
  const { control = methods.control, name, keyName = 'id', shouldUnregister, } = props;
442
647
  const [fields, setFields] = React.useState(control._getFieldArray(name));
@@ -460,89 +665,89 @@ const useFieldArray = (props) => {
460
665
  });
461
666
  const updateValues = React.useCallback((updatedFieldArrayValues) => {
462
667
  _actioned.current = true;
463
- set(control._formValues, name, updatedFieldArrayValues);
668
+ control._updateFieldArray(name, updatedFieldArrayValues);
464
669
  }, [control, name]);
465
670
  const append$1 = (value, options) => {
466
671
  const appendValue = convertToArrayPayload(cloneObject(value));
467
672
  const updatedFieldArrayValues = append(control._getFieldArray(name), appendValue);
468
673
  control._names.focus = getFocusFieldName(name, updatedFieldArrayValues.length - 1, options);
469
674
  ids.current = append(ids.current, appendValue.map(generateId));
470
- setFields(updatedFieldArrayValues);
471
675
  updateValues(updatedFieldArrayValues);
472
- control._updateFieldArray(name, append, {
676
+ setFields(updatedFieldArrayValues);
677
+ control._updateFieldArray(name, updatedFieldArrayValues, append, {
473
678
  argA: fillEmptyArray(value),
474
- }, updatedFieldArrayValues);
679
+ });
475
680
  };
476
681
  const prepend$1 = (value, options) => {
477
682
  const prependValue = convertToArrayPayload(cloneObject(value));
478
683
  const updatedFieldArrayValues = prepend(control._getFieldArray(name), prependValue);
479
684
  control._names.focus = getFocusFieldName(name, 0, options);
480
685
  ids.current = prepend(ids.current, prependValue.map(generateId));
481
- setFields(updatedFieldArrayValues);
482
686
  updateValues(updatedFieldArrayValues);
483
- control._updateFieldArray(name, prepend, {
687
+ setFields(updatedFieldArrayValues);
688
+ control._updateFieldArray(name, updatedFieldArrayValues, prepend, {
484
689
  argA: fillEmptyArray(value),
485
- }, updatedFieldArrayValues);
690
+ });
486
691
  };
487
692
  const remove = (index) => {
488
693
  const updatedFieldArrayValues = removeArrayAt(control._getFieldArray(name), index);
489
694
  ids.current = removeArrayAt(ids.current, index);
490
- setFields(updatedFieldArrayValues);
491
695
  updateValues(updatedFieldArrayValues);
492
- control._updateFieldArray(name, removeArrayAt, {
696
+ setFields(updatedFieldArrayValues);
697
+ control._updateFieldArray(name, updatedFieldArrayValues, removeArrayAt, {
493
698
  argA: index,
494
- }, updatedFieldArrayValues);
699
+ });
495
700
  };
496
701
  const insert$1 = (index, value, options) => {
497
702
  const insertValue = convertToArrayPayload(cloneObject(value));
498
703
  const updatedFieldArrayValues = insert(control._getFieldArray(name), index, insertValue);
499
- updateValues(updatedFieldArrayValues);
500
704
  control._names.focus = getFocusFieldName(name, index, options);
501
705
  ids.current = insert(ids.current, index, insertValue.map(generateId));
706
+ updateValues(updatedFieldArrayValues);
502
707
  setFields(updatedFieldArrayValues);
503
- control._updateFieldArray(name, insert, {
708
+ control._updateFieldArray(name, updatedFieldArrayValues, insert, {
504
709
  argA: index,
505
710
  argB: fillEmptyArray(value),
506
- }, updatedFieldArrayValues);
711
+ });
507
712
  };
508
713
  const swap = (indexA, indexB) => {
509
714
  const updatedFieldArrayValues = control._getFieldArray(name);
510
715
  swapArrayAt(updatedFieldArrayValues, indexA, indexB);
511
716
  swapArrayAt(ids.current, indexA, indexB);
512
- setFields(updatedFieldArrayValues);
513
717
  updateValues(updatedFieldArrayValues);
514
- control._updateFieldArray(name, swapArrayAt, {
718
+ setFields(updatedFieldArrayValues);
719
+ control._updateFieldArray(name, updatedFieldArrayValues, swapArrayAt, {
515
720
  argA: indexA,
516
721
  argB: indexB,
517
- }, updatedFieldArrayValues, false);
722
+ }, false);
518
723
  };
519
724
  const move = (from, to) => {
520
725
  const updatedFieldArrayValues = control._getFieldArray(name);
521
726
  moveArrayAt(updatedFieldArrayValues, from, to);
522
727
  moveArrayAt(ids.current, from, to);
523
- setFields(updatedFieldArrayValues);
524
728
  updateValues(updatedFieldArrayValues);
525
- control._updateFieldArray(name, moveArrayAt, {
729
+ setFields(updatedFieldArrayValues);
730
+ control._updateFieldArray(name, updatedFieldArrayValues, moveArrayAt, {
526
731
  argA: from,
527
732
  argB: to,
528
- }, updatedFieldArrayValues, false);
733
+ }, false);
529
734
  };
530
735
  const update = (index, value) => {
531
736
  const updatedFieldArrayValues = updateAt(control._getFieldArray(name), index, value);
532
737
  ids.current = [...updatedFieldArrayValues].map((item, i) => !item || i === index ? generateId() : ids.current[i]);
533
- setFields([...updatedFieldArrayValues]);
534
738
  updateValues(updatedFieldArrayValues);
535
- control._updateFieldArray(name, updateAt, {
739
+ setFields([...updatedFieldArrayValues]);
740
+ control._updateFieldArray(name, updatedFieldArrayValues, updateAt, {
536
741
  argA: index,
537
742
  argB: value,
538
- }, updatedFieldArrayValues, true, false);
743
+ }, true, false);
539
744
  };
540
745
  const replace = (value) => {
541
- const updatedFieldArrayValues = convertToArrayPayload(value);
746
+ const updatedFieldArrayValues = convertToArrayPayload(cloneObject(value));
542
747
  ids.current = updatedFieldArrayValues.map(generateId);
543
748
  updateValues([...updatedFieldArrayValues]);
544
749
  setFields([...updatedFieldArrayValues]);
545
- control._updateFieldArray(name, () => updatedFieldArrayValues, {}, [...updatedFieldArrayValues], true, false);
750
+ control._updateFieldArray(name, [...updatedFieldArrayValues], (data) => data, {}, true, false);
546
751
  };
547
752
  React.useEffect(() => {
548
753
  control._stateFlags.action = false;
@@ -568,7 +773,7 @@ const useFieldArray = (props) => {
568
773
  control._proxyFormState.isValid && control._updateValid();
569
774
  }, [fields, name, control]);
570
775
  React.useEffect(() => {
571
- !get(control._formValues, name) && set(control._formValues, name, []);
776
+ !get(control._formValues, name) && control._updateFieldArray(name);
572
777
  return () => {
573
778
  (control._options.shouldUnregister || shouldUnregister) &&
574
779
  control.unregister(name);
@@ -585,7 +790,7 @@ const useFieldArray = (props) => {
585
790
  replace: React.useCallback(replace, [updateValues, name, control]),
586
791
  fields: React.useMemo(() => fields.map((field, index) => (Object.assign(Object.assign({}, field), { [keyName]: ids.current[index] || generateId() }))), [fields, keyName]),
587
792
  };
588
- };
793
+ }
589
794
 
590
795
  function createSubject() {
591
796
  let _observers = [];
@@ -974,8 +1179,7 @@ var validateField = async (field, inputValue, validateAllFieldCriteria, shouldUs
974
1179
  const maxOutput = getValueAndMessage(max);
975
1180
  const minOutput = getValueAndMessage(min);
976
1181
  if (!isNaN(inputValue)) {
977
- const valueNumber = ref.valueAsNumber ||
978
- parseFloat(inputValue);
1182
+ const valueNumber = ref.valueAsNumber || +inputValue;
979
1183
  if (!isNullOrUndefined(maxOutput.value)) {
980
1184
  exceedMax = valueNumber > maxOutput.value;
981
1185
  }
@@ -1138,33 +1342,38 @@ function createFormControl(props = {}) {
1138
1342
  }
1139
1343
  return isValid;
1140
1344
  };
1141
- const _updateFieldArray = (name, method, args, values = [], shouldSetValues = true, shouldSetFields = true) => {
1142
- _stateFlags.action = true;
1143
- if (shouldSetFields && Array.isArray(get(_fields, name))) {
1144
- const fieldValues = method(get(_fields, name), args.argA, args.argB);
1145
- shouldSetValues && set(_fields, name, fieldValues);
1146
- }
1147
- if (_proxyFormState.errors &&
1148
- shouldSetFields &&
1149
- Array.isArray(get(_formState.errors, name))) {
1150
- const errors = method(get(_formState.errors, name), args.argA, args.argB);
1151
- shouldSetValues && set(_formState.errors, name, errors);
1152
- unsetEmptyArray(_formState.errors, name);
1153
- }
1154
- if (_proxyFormState.touchedFields &&
1155
- Array.isArray(get(_formState.touchedFields, name))) {
1156
- const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
1157
- shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1345
+ const _updateFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndErrors = true) => {
1346
+ if (args && method) {
1347
+ _stateFlags.action = true;
1348
+ if (shouldUpdateFieldsAndErrors && Array.isArray(get(_fields, name))) {
1349
+ const fieldValues = method(get(_fields, name), args.argA, args.argB);
1350
+ shouldSetValues && set(_fields, name, fieldValues);
1351
+ }
1352
+ if (_proxyFormState.errors &&
1353
+ shouldUpdateFieldsAndErrors &&
1354
+ Array.isArray(get(_formState.errors, name))) {
1355
+ const errors = method(get(_formState.errors, name), args.argA, args.argB);
1356
+ shouldSetValues && set(_formState.errors, name, errors);
1357
+ unsetEmptyArray(_formState.errors, name);
1358
+ }
1359
+ if (_proxyFormState.touchedFields &&
1360
+ Array.isArray(get(_formState.touchedFields, name))) {
1361
+ const touchedFields = method(get(_formState.touchedFields, name), args.argA, args.argB);
1362
+ shouldSetValues && set(_formState.touchedFields, name, touchedFields);
1363
+ }
1364
+ if (_proxyFormState.dirtyFields) {
1365
+ _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1366
+ }
1367
+ _subjects.state.next({
1368
+ isDirty: _getDirty(name, values),
1369
+ dirtyFields: _formState.dirtyFields,
1370
+ errors: _formState.errors,
1371
+ isValid: _formState.isValid,
1372
+ });
1158
1373
  }
1159
- if (_proxyFormState.dirtyFields) {
1160
- _formState.dirtyFields = getDirtyFields(_defaultValues, _formValues);
1374
+ else {
1375
+ set(_formValues, name, values);
1161
1376
  }
1162
- _subjects.state.next({
1163
- isDirty: _getDirty(name, values),
1164
- dirtyFields: _formState.dirtyFields,
1165
- errors: _formState.errors,
1166
- isValid: _formState.isValid,
1167
- });
1168
1377
  };
1169
1378
  const updateErrors = (name, error) => (set(_formState.errors, name, error),
1170
1379
  _subjects.state.next({
@@ -1238,7 +1447,8 @@ function createFormControl(props = {}) {
1238
1447
  _subjects.state.next(updatedFormState);
1239
1448
  }
1240
1449
  validateFields[name]--;
1241
- if (_proxyFormState.isValidating && !validateFields[name]) {
1450
+ if (_proxyFormState.isValidating &&
1451
+ !Object.values(validateFields).some((v) => v)) {
1242
1452
  _subjects.state.next({
1243
1453
  isValidating: false,
1244
1454
  });
@@ -1343,7 +1553,10 @@ function createFormControl(props = {}) {
1343
1553
  fieldReference.refs.forEach((radioRef) => (radioRef.checked = radioRef.value === fieldValue));
1344
1554
  }
1345
1555
  }
1346
- else if (!isFileInput(fieldReference.ref)) {
1556
+ else if (isFileInput(fieldReference.ref)) {
1557
+ fieldReference.ref.value = '';
1558
+ }
1559
+ else {
1347
1560
  fieldReference.ref.value = fieldValue;
1348
1561
  if (!fieldReference.ref.type) {
1349
1562
  _subjects.watch.next({
@@ -1410,7 +1623,7 @@ function createFormControl(props = {}) {
1410
1623
  const fieldValue = target.type
1411
1624
  ? getFieldValue(field._f)
1412
1625
  : getEventValue(event);
1413
- const isBlurEvent = event.type === EVENTS.BLUR;
1626
+ const isBlurEvent = event.type === EVENTS.BLUR || event.type === EVENTS.FOCUS_OUT;
1414
1627
  const shouldSkipValidation = (!hasValidation(field._f) &&
1415
1628
  !_options.resolver &&
1416
1629
  !get(_formState.errors, name) &&
@@ -1437,10 +1650,9 @@ function createFormControl(props = {}) {
1437
1650
  }
1438
1651
  !isBlurEvent && watched && _subjects.state.next({});
1439
1652
  validateFields[name] = validateFields[name] ? +1 : 1;
1440
- _proxyFormState.isValidating &&
1441
- _subjects.state.next({
1442
- isValidating: true,
1443
- });
1653
+ _subjects.state.next({
1654
+ isValidating: true,
1655
+ });
1444
1656
  if (_options.resolver) {
1445
1657
  const { errors } = await _executeSchema([name]);
1446
1658
  const previousErrorLookupResult = schemaErrorLookup(_formState.errors, _fields, name);
@@ -1614,9 +1826,7 @@ function createFormControl(props = {}) {
1614
1826
  e.persist && e.persist();
1615
1827
  }
1616
1828
  let hasNoPromiseError = true;
1617
- let fieldValues = _options.shouldUnregister
1618
- ? cloneObject(_formValues)
1619
- : Object.assign({}, _formValues);
1829
+ let fieldValues = cloneObject(_formValues);
1620
1830
  _subjects.state.next({
1621
1831
  isSubmitting: true,
1622
1832
  });
@@ -1638,7 +1848,9 @@ function createFormControl(props = {}) {
1638
1848
  await onValid(fieldValues, e);
1639
1849
  }
1640
1850
  else {
1641
- onInvalid && (await onInvalid(_formState.errors, e));
1851
+ if (onInvalid) {
1852
+ await onInvalid(Object.assign({}, _formState.errors), e);
1853
+ }
1642
1854
  _options.shouldFocusError &&
1643
1855
  focusFieldBy(_fields, (key) => get(_formState.errors, key), _names.mount);
1644
1856
  }
@@ -1781,15 +1993,9 @@ function createFormControl(props = {}) {
1781
1993
  get _fields() {
1782
1994
  return _fields;
1783
1995
  },
1784
- set _fields(value) {
1785
- _fields = value;
1786
- },
1787
1996
  get _formValues() {
1788
1997
  return _formValues;
1789
1998
  },
1790
- set _formValues(value) {
1791
- _formValues = value;
1792
- },
1793
1999
  get _stateFlags() {
1794
2000
  return _stateFlags;
1795
2001
  },
@@ -1799,9 +2005,6 @@ function createFormControl(props = {}) {
1799
2005
  get _defaultValues() {
1800
2006
  return _defaultValues;
1801
2007
  },
1802
- set _defaultValues(value) {
1803
- _defaultValues = value;
1804
- },
1805
2008
  get _names() {
1806
2009
  return _names;
1807
2010
  },
@@ -1837,6 +2040,35 @@ function createFormControl(props = {}) {
1837
2040
  };
1838
2041
  }
1839
2042
 
2043
+ /**
2044
+ * Custom hook to mange the entire form.
2045
+ *
2046
+ * @remarks
2047
+ * [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)
2048
+ *
2049
+ * @param props - form configuration and validation parameters.
2050
+ *
2051
+ * @returns methods - individual functions to manage the form state. {@link UseFormReturn}
2052
+ *
2053
+ * @example
2054
+ * ```tsx
2055
+ * function App() {
2056
+ * const { register, handleSubmit, watch, formState: { errors } } = useForm();
2057
+ * const onSubmit = data => console.log(data);
2058
+ *
2059
+ * console.log(watch("example"));
2060
+ *
2061
+ * return (
2062
+ * <form onSubmit={handleSubmit(onSubmit)}>
2063
+ * <input defaultValue="test" {...register("example")} />
2064
+ * <input {...register("exampleRequired", { required: true })} />
2065
+ * {errors.exampleRequired && <span>This field is required</span>}
2066
+ * <input type="submit" />
2067
+ * </form>
2068
+ * );
2069
+ * }
2070
+ * ```
2071
+ */
1840
2072
  function useForm(props = {}) {
1841
2073
  const _formControl = React.useRef();
1842
2074
  const [formState, updateFormState] = React.useState({