react-hook-form 7.86.0 → 7.88.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.
- package/dist/controller.d.ts +7 -35
- package/dist/controller.d.ts.map +1 -1
- package/dist/errorMessage.d.ts +27 -0
- package/dist/errorMessage.d.ts.map +1 -0
- package/dist/form.d.ts +7 -15
- package/dist/form.d.ts.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.mjs +317 -313
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.react-server.d.ts +3 -0
- package/dist/index.react-server.d.ts.map +1 -0
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/logic/createFormControl.d.ts.map +1 -1
- package/dist/logic/getNullAncestorValue.d.ts +5 -0
- package/dist/logic/getNullAncestorValue.d.ts.map +1 -0
- package/dist/logic/iterateFieldsByAction.d.ts +1 -1
- package/dist/logic/iterateFieldsByAction.d.ts.map +1 -1
- package/dist/logic/schemaErrorLookup.d.ts.map +1 -1
- package/dist/logic/validateField.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +2464 -0
- package/dist/react-server.esm.mjs.map +1 -0
- package/dist/types/errors.d.ts +3 -3
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/form.d.ts +2 -1
- package/dist/types/form.d.ts.map +1 -1
- package/dist/types/path/eager.d.ts +3 -3
- package/dist/types/path/eager.d.ts.map +1 -1
- package/dist/types/utils.d.ts +29 -4
- package/dist/types/utils.d.ts.map +1 -1
- package/dist/useController.d.ts +5 -17
- package/dist/useController.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts +5 -30
- package/dist/useFieldArray.d.ts.map +1 -1
- package/dist/useForm.d.ts +7 -22
- package/dist/useForm.d.ts.map +1 -1
- package/dist/useFormContext.d.ts +10 -46
- package/dist/useFormContext.d.ts.map +1 -1
- package/dist/useFormState.d.ts +4 -23
- package/dist/useFormState.d.ts.map +1 -1
- package/dist/useResyncOnReconnect.d.ts +1 -1
- package/dist/useResyncOnReconnect.d.ts.map +1 -1
- package/dist/useWatch.d.ts +7 -140
- package/dist/useWatch.d.ts.map +1 -1
- package/dist/utils/cloneObject.d.ts.map +1 -1
- package/dist/utils/flatten.d.ts.map +1 -1
- package/dist/utils/formData.d.ts.map +1 -1
- package/dist/watch.d.ts +4 -16
- package/dist/watch.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.mjs
CHANGED
|
@@ -22,6 +22,24 @@ var getEventValue = (event) => isObject(event) && event.target
|
|
|
22
22
|
: event.target.value
|
|
23
23
|
: event;
|
|
24
24
|
|
|
25
|
+
const FIELD_PATH_RE = /[.[\]'"]/;
|
|
26
|
+
var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
|
|
27
|
+
|
|
28
|
+
function getNullAncestorValue(control, name) {
|
|
29
|
+
const segments = stringToPath(name);
|
|
30
|
+
let formValues = control._formValues;
|
|
31
|
+
let defaultValues = control._defaultValues;
|
|
32
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
33
|
+
const key = segments[i];
|
|
34
|
+
formValues = formValues == null ? formValues : formValues[key];
|
|
35
|
+
defaultValues = defaultValues == null ? defaultValues : defaultValues[key];
|
|
36
|
+
if (formValues === null || defaultValues === null) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
25
43
|
var isNameInFieldArray = (names, name) => name
|
|
26
44
|
.split('.')
|
|
27
45
|
.some((part, index, arr) => !isNaN(Number(part)) && names.has(arr.slice(0, index).join('.')));
|
|
@@ -37,8 +55,9 @@ function cloneObject(data) {
|
|
|
37
55
|
if (data instanceof Date) {
|
|
38
56
|
return new Date(data);
|
|
39
57
|
}
|
|
58
|
+
const isBlobInstance = typeof Blob !== 'undefined' && data instanceof Blob;
|
|
40
59
|
const isFileListInstance = typeof FileList !== 'undefined' && data instanceof FileList;
|
|
41
|
-
if (isWeb && (
|
|
60
|
+
if (isWeb && (isBlobInstance || isFileListInstance)) {
|
|
42
61
|
return data;
|
|
43
62
|
}
|
|
44
63
|
const isArray = Array.isArray(data);
|
|
@@ -86,9 +105,6 @@ var isKey = (value) => IS_KEY_RE.test(value);
|
|
|
86
105
|
|
|
87
106
|
var isUndefined = (val) => val === undefined;
|
|
88
107
|
|
|
89
|
-
const FIELD_PATH_RE = /[.[\]'"]/;
|
|
90
|
-
var stringToPath = (input) => input.split(FIELD_PATH_RE).filter(Boolean);
|
|
91
|
-
|
|
92
108
|
var get = (object, path, defaultValue) => {
|
|
93
109
|
if (!path || !isObject(object)) {
|
|
94
110
|
return defaultValue;
|
|
@@ -229,11 +245,20 @@ function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
|
229
245
|
return true;
|
|
230
246
|
}
|
|
231
247
|
|
|
232
|
-
function useResyncOnReconnect() {
|
|
248
|
+
function useResyncOnReconnect(getInitialValue) {
|
|
233
249
|
const _connected = React.useRef(false);
|
|
250
|
+
const _initialized = React.useRef(false);
|
|
234
251
|
const _prevValue = React.useRef(undefined);
|
|
252
|
+
const _renderCount = React.useRef(0);
|
|
253
|
+
_renderCount.current++;
|
|
254
|
+
if (!_initialized.current && getInitialValue) {
|
|
255
|
+
_initialized.current = true;
|
|
256
|
+
_prevValue.current = cloneObject(getInitialValue());
|
|
257
|
+
}
|
|
235
258
|
const resyncIfNeeded = React.useCallback((enabled, getCurrentValue, setValue) => {
|
|
236
|
-
if (enabled &&
|
|
259
|
+
if (enabled &&
|
|
260
|
+
(_connected.current ||
|
|
261
|
+
(_initialized.current && _renderCount.current > 1))) {
|
|
237
262
|
const currentValue = getCurrentValue();
|
|
238
263
|
if (!deepEqual(_prevValue.current, currentValue)) {
|
|
239
264
|
setValue(currentValue);
|
|
@@ -250,42 +275,24 @@ function useResyncOnReconnect() {
|
|
|
250
275
|
}
|
|
251
276
|
|
|
252
277
|
/**
|
|
253
|
-
* Subscribes to
|
|
254
|
-
*
|
|
255
|
-
* @remarks
|
|
256
|
-
* [API](https://react-hook-form.com/docs/useformstate) • [Demo](https://codesandbox.io/s/useformstate-75xly)
|
|
278
|
+
* Subscribes to form state with re-renders isolated to this hook.
|
|
279
|
+
* Optionally scope to specific field names to minimize re-render surface.
|
|
257
280
|
*
|
|
258
|
-
* @
|
|
281
|
+
* @see [API](https://react-hook-form.com/docs/useformstate)
|
|
259
282
|
*
|
|
260
283
|
* @example
|
|
261
284
|
* ```tsx
|
|
262
|
-
*
|
|
263
|
-
* const { register, handleSubmit, control } = useForm({
|
|
264
|
-
* defaultValues: {
|
|
265
|
-
* firstName: "firstName"
|
|
266
|
-
* }});
|
|
267
|
-
* const { dirtyFields } = useFormState({
|
|
268
|
-
* control
|
|
269
|
-
* });
|
|
270
|
-
* const onSubmit = (data) => console.log(data);
|
|
271
|
-
*
|
|
272
|
-
* return (
|
|
273
|
-
* <form onSubmit={handleSubmit(onSubmit)}>
|
|
274
|
-
* <input {...register("firstName")} placeholder="First Name" />
|
|
275
|
-
* {dirtyFields.firstName && <p>Field is dirty.</p>}
|
|
276
|
-
* <input type="submit" />
|
|
277
|
-
* </form>
|
|
278
|
-
* );
|
|
279
|
-
* }
|
|
285
|
+
* const { errors, isDirty } = useFormState({ control, name: "email" });
|
|
280
286
|
* ```
|
|
281
287
|
*/
|
|
282
288
|
function useFormState(props) {
|
|
283
289
|
const formControl = useFormControlContext();
|
|
284
290
|
const { control = formControl, disabled, name, exact } = props || {};
|
|
285
|
-
const
|
|
291
|
+
const getCurrentFormState = () => ({
|
|
286
292
|
...control._formState,
|
|
287
293
|
defaultValues: control._defaultValues,
|
|
288
|
-
})
|
|
294
|
+
});
|
|
295
|
+
const [formState, updateFormState] = React.useState(getCurrentFormState);
|
|
289
296
|
const _localProxyFormState = React.useRef({
|
|
290
297
|
isDirty: false,
|
|
291
298
|
isLoading: false,
|
|
@@ -296,12 +303,8 @@ function useFormState(props) {
|
|
|
296
303
|
isValid: false,
|
|
297
304
|
errors: false,
|
|
298
305
|
});
|
|
299
|
-
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
306
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect(getCurrentFormState);
|
|
300
307
|
useIsomorphicLayoutEffect(() => {
|
|
301
|
-
const getCurrentFormState = () => ({
|
|
302
|
-
...control._formState,
|
|
303
|
-
defaultValues: control._defaultValues,
|
|
304
|
-
});
|
|
305
308
|
resyncIfNeeded(!disabled, getCurrentFormState, updateFormState);
|
|
306
309
|
const unsubscribe = control._subscribe({
|
|
307
310
|
name,
|
|
@@ -320,7 +323,7 @@ function useFormState(props) {
|
|
|
320
323
|
unsubscribe();
|
|
321
324
|
snapshot(!disabled, getCurrentFormState);
|
|
322
325
|
};
|
|
323
|
-
}, [name, disabled, exact, resyncIfNeeded, snapshot]);
|
|
326
|
+
}, [control, name, disabled, exact, resyncIfNeeded, snapshot]);
|
|
324
327
|
React.useEffect(() => {
|
|
325
328
|
_localProxyFormState.current.isValid && control._setValid(true);
|
|
326
329
|
}, [control]);
|
|
@@ -336,26 +339,22 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
336
339
|
}
|
|
337
340
|
if (Array.isArray(names)) {
|
|
338
341
|
return names.map((fieldName) => (isGlobal && _names.watch.add(fieldName),
|
|
339
|
-
get(formValues, fieldName)));
|
|
342
|
+
get(formValues, fieldName, get(defaultValue, fieldName))));
|
|
340
343
|
}
|
|
341
344
|
isGlobal && (_names.watchAll = true);
|
|
342
345
|
return formValues;
|
|
343
346
|
};
|
|
344
347
|
|
|
345
348
|
/**
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
* @remarks
|
|
349
|
+
* Subscribes to field value changes and isolates re-renders to the hook level.
|
|
349
350
|
*
|
|
350
|
-
* [API](https://react-hook-form.com/docs/usewatch)
|
|
351
|
+
* @see [API](https://react-hook-form.com/docs/usewatch)
|
|
351
352
|
*
|
|
352
353
|
* @example
|
|
353
354
|
* ```tsx
|
|
354
|
-
* const { control
|
|
355
|
-
* const
|
|
356
|
-
*
|
|
357
|
-
* control,
|
|
358
|
-
* })
|
|
355
|
+
* const email = useWatch({ control, name: "email" });
|
|
356
|
+
* const all = useWatch({ control });
|
|
357
|
+
* const adult = useWatch({ control, name: "age", compute: (v) => v >= 18 });
|
|
359
358
|
* ```
|
|
360
359
|
*/
|
|
361
360
|
function useWatch(props) {
|
|
@@ -363,14 +362,15 @@ function useWatch(props) {
|
|
|
363
362
|
const { control = formControl, name, defaultValue, disabled, exact, compute, } = props || {};
|
|
364
363
|
const _defaultValue = React.useRef(defaultValue);
|
|
365
364
|
const _compute = React.useRef(compute);
|
|
366
|
-
const _computeFormValues = React.useRef(undefined);
|
|
367
365
|
const _prevControl = React.useRef(control);
|
|
368
366
|
const _prevName = React.useRef(name);
|
|
369
367
|
_compute.current = compute;
|
|
370
|
-
const
|
|
368
|
+
const getInitialOutput = () => {
|
|
371
369
|
const defaultValue = control._getWatch(name, _defaultValue.current);
|
|
372
370
|
return _compute.current ? _compute.current(defaultValue) : defaultValue;
|
|
373
|
-
}
|
|
371
|
+
};
|
|
372
|
+
const [value, updateValue] = React.useState(getInitialOutput);
|
|
373
|
+
const _computeFormValues = React.useRef(value);
|
|
374
374
|
const getCurrentOutput = React.useCallback((values) => {
|
|
375
375
|
const formValues = generateWatchOutput(name, control._names, values || control._formValues, false, _defaultValue.current);
|
|
376
376
|
return _compute.current ? _compute.current(formValues) : formValues;
|
|
@@ -390,7 +390,7 @@ function useWatch(props) {
|
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
392
|
}, [control._formValues, control._names, disabled, name]);
|
|
393
|
-
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
393
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect(getInitialOutput);
|
|
394
394
|
const _refreshValue = React.useRef(refreshValue);
|
|
395
395
|
_refreshValue.current = refreshValue;
|
|
396
396
|
const _getCurrentOutput = React.useRef(getCurrentOutput);
|
|
@@ -444,34 +444,27 @@ function useWatch(props) {
|
|
|
444
444
|
}
|
|
445
445
|
|
|
446
446
|
/**
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
* @remarks
|
|
450
|
-
* [API](https://react-hook-form.com/docs/usecontroller) • [Demo](https://codesandbox.io/s/usecontroller-0o8px)
|
|
447
|
+
* Hook for controlled inputs. Returns `field`, `fieldState`, and `formState`.
|
|
448
|
+
* Re-renders are isolated to the hook level.
|
|
451
449
|
*
|
|
452
|
-
* @
|
|
453
|
-
*
|
|
454
|
-
* @returns field properties, field and form state. {@link UseControllerReturn}
|
|
450
|
+
* @see [API](https://react-hook-form.com/docs/usecontroller)
|
|
455
451
|
*
|
|
456
452
|
* @example
|
|
457
453
|
* ```tsx
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
* return (
|
|
461
|
-
* <div>
|
|
462
|
-
* <input {...field} placeholder={props.name} />
|
|
463
|
-
* <p>{fieldState.isTouched && "Touched"}</p>
|
|
464
|
-
* <p>{formState.isSubmitted ? "submitted" : ""}</p>
|
|
465
|
-
* </div>
|
|
466
|
-
* );
|
|
467
|
-
* }
|
|
454
|
+
* const { field, fieldState } = useController({ control, name: "email" });
|
|
455
|
+
* return <input {...field} />;
|
|
468
456
|
* ```
|
|
469
457
|
*/
|
|
470
458
|
function useController(props) {
|
|
471
459
|
const formControl = useFormControlContext();
|
|
472
460
|
const { name, disabled, control = formControl, shouldUnregister, defaultValue, exact = true, } = props;
|
|
473
461
|
const isArrayField = isNameInFieldArray(control._names.array, name);
|
|
474
|
-
const defaultValueMemo = React.useMemo(() =>
|
|
462
|
+
const defaultValueMemo = React.useMemo(() => {
|
|
463
|
+
const resolved = get(control._formValues, name, get(control._defaultValues, name, defaultValue));
|
|
464
|
+
return isUndefined(resolved)
|
|
465
|
+
? getNullAncestorValue(control, name)
|
|
466
|
+
: resolved;
|
|
467
|
+
}, [control, name, defaultValue]);
|
|
475
468
|
const value = useWatch({
|
|
476
469
|
control,
|
|
477
470
|
name,
|
|
@@ -613,48 +606,50 @@ function useController(props) {
|
|
|
613
606
|
}
|
|
614
607
|
|
|
615
608
|
/**
|
|
616
|
-
* Component
|
|
609
|
+
* Component wrapper around `useController` for controlled inputs.
|
|
617
610
|
*
|
|
618
|
-
* @
|
|
619
|
-
* [API](https://react-hook-form.com/docs/usecontroller/controller) • [Demo](https://codesandbox.io/s/react-hook-form-v6-controller-ts-jwyzw) • [Video](https://www.youtube.com/watch?v=N2UNk_UCVyA)
|
|
611
|
+
* @see [API](https://react-hook-form.com/docs/usecontroller/controller)
|
|
620
612
|
*
|
|
621
|
-
* @
|
|
613
|
+
* @example
|
|
614
|
+
* ```tsx
|
|
615
|
+
* <Controller
|
|
616
|
+
* control={control}
|
|
617
|
+
* name="test"
|
|
618
|
+
* render={({ field, fieldState, formState }) => <input {...field} />}
|
|
619
|
+
* />
|
|
620
|
+
* ```
|
|
621
|
+
*/
|
|
622
|
+
const Controller = (props) => props.render(useController(props));
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Displays the validation error for a single field.
|
|
626
|
+
* Reads from `control` when provided, otherwise from the nearest `FormProvider`.
|
|
622
627
|
*
|
|
623
|
-
* @
|
|
628
|
+
* @see [API](https://react-hook-form.com/docs/useformstate/errormessage)
|
|
624
629
|
*
|
|
625
630
|
* @example
|
|
626
631
|
* ```tsx
|
|
627
|
-
*
|
|
628
|
-
*
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
* }
|
|
632
|
-
* });
|
|
633
|
-
*
|
|
634
|
-
* return (
|
|
635
|
-
* <form>
|
|
636
|
-
* <Controller
|
|
637
|
-
* control={control}
|
|
638
|
-
* name="test"
|
|
639
|
-
* render={({ field: { onChange, onBlur, value, ref }, formState, fieldState }) => (
|
|
640
|
-
* <>
|
|
641
|
-
* <input
|
|
642
|
-
* onChange={onChange} // send value to hook form
|
|
643
|
-
* onBlur={onBlur} // notify when input is touched
|
|
644
|
-
* value={value} // return updated value
|
|
645
|
-
* ref={ref} // set ref for focus management
|
|
646
|
-
* />
|
|
647
|
-
* <p>{formState.isSubmitted ? "submitted" : ""}</p>
|
|
648
|
-
* <p>{fieldState.isTouched ? "touched" : ""}</p>
|
|
649
|
-
* </>
|
|
650
|
-
* )}
|
|
651
|
-
* />
|
|
652
|
-
* </form>
|
|
653
|
-
* );
|
|
654
|
-
* }
|
|
632
|
+
* <ErrorMessage control={control} name="email" as="p" />
|
|
633
|
+
* <ErrorMessage name="email" as="span" />
|
|
634
|
+
* <ErrorMessage control={control} name="email"
|
|
635
|
+
* render={({ message }) => <Alert>{message}</Alert>} />
|
|
655
636
|
* ```
|
|
656
637
|
*/
|
|
657
|
-
const
|
|
638
|
+
const ErrorMessage = ({ as, control, name, render, }) => {
|
|
639
|
+
const { errors } = useFormState({
|
|
640
|
+
control,
|
|
641
|
+
name: name,
|
|
642
|
+
});
|
|
643
|
+
const error = get(errors, name);
|
|
644
|
+
if (!error) {
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
const message = error.message || '';
|
|
648
|
+
if (render) {
|
|
649
|
+
return render({ message, messages: error.types });
|
|
650
|
+
}
|
|
651
|
+
return React.createElement(as || React.Fragment, null, message);
|
|
652
|
+
};
|
|
658
653
|
|
|
659
654
|
var generateId = () => typeof crypto !== 'undefined' && crypto.randomUUID
|
|
660
655
|
? crypto.randomUUID()
|
|
@@ -688,7 +683,7 @@ var isWatched = (name, _names, isBlurEvent) => {
|
|
|
688
683
|
return false;
|
|
689
684
|
};
|
|
690
685
|
|
|
691
|
-
const iterateFieldsByAction = (fields, action, fieldsNames
|
|
686
|
+
const iterateFieldsByAction = (fields, action, fieldsNames) => {
|
|
692
687
|
for (const key of fieldsNames || Object.keys(fields)) {
|
|
693
688
|
if (key === '_f') {
|
|
694
689
|
continue;
|
|
@@ -697,21 +692,21 @@ const iterateFieldsByAction = (fields, action, fieldsNames, abortEarly) => {
|
|
|
697
692
|
if (field) {
|
|
698
693
|
const { _f } = field;
|
|
699
694
|
if (_f) {
|
|
700
|
-
if (_f.refs && _f.refs[0] && action(_f.refs[0],
|
|
695
|
+
if (_f.refs && _f.refs[0] && action(_f.refs[0], _f.name)) {
|
|
701
696
|
return true;
|
|
702
697
|
}
|
|
703
|
-
else if (_f.ref && action(_f.ref, _f.name)
|
|
698
|
+
else if (_f.ref && action(_f.ref, _f.name)) {
|
|
704
699
|
return true;
|
|
705
700
|
}
|
|
706
701
|
else {
|
|
707
702
|
if (iterateFieldsByAction(field, action)) {
|
|
708
|
-
|
|
703
|
+
return true;
|
|
709
704
|
}
|
|
710
705
|
}
|
|
711
706
|
}
|
|
712
707
|
else if (isObject(field) || Array.isArray(field)) {
|
|
713
708
|
if (iterateFieldsByAction(field, action)) {
|
|
714
|
-
|
|
709
|
+
return true;
|
|
715
710
|
}
|
|
716
711
|
}
|
|
717
712
|
}
|
|
@@ -977,7 +972,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
977
972
|
...validateError,
|
|
978
973
|
...appendErrorsCurry(key, validateError.message),
|
|
979
974
|
};
|
|
980
|
-
|
|
975
|
+
if (!validateAllFieldCriteria) {
|
|
976
|
+
setCustomValidity(validateError.message);
|
|
977
|
+
}
|
|
981
978
|
if (validateAllFieldCriteria) {
|
|
982
979
|
error[name] = validationResult;
|
|
983
980
|
}
|
|
@@ -1105,48 +1102,27 @@ var updateAt = (fieldValues, index, value) => {
|
|
|
1105
1102
|
};
|
|
1106
1103
|
|
|
1107
1104
|
/**
|
|
1108
|
-
*
|
|
1109
|
-
*
|
|
1110
|
-
* @remarks
|
|
1111
|
-
* [API](https://react-hook-form.com/docs/usefieldarray) • [Demo](https://codesandbox.io/s/react-hook-form-usefieldarray-ssugn)
|
|
1112
|
-
*
|
|
1113
|
-
* @param props - useFieldArray props
|
|
1105
|
+
* Hook for dynamic field arrays. Provides `fields` and mutation methods:
|
|
1106
|
+
* `append`, `prepend`, `remove`, `insert`, `swap`, `move`, `update`, `replace`.
|
|
1114
1107
|
*
|
|
1115
|
-
* @
|
|
1108
|
+
* @see [API](https://react-hook-form.com/docs/usefieldarray)
|
|
1116
1109
|
*
|
|
1117
1110
|
* @example
|
|
1118
1111
|
* ```tsx
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1121
|
-
* defaultValues: {
|
|
1122
|
-
* test: []
|
|
1123
|
-
* }
|
|
1124
|
-
* });
|
|
1125
|
-
* const { fields, append } = useFieldArray({
|
|
1126
|
-
* control,
|
|
1127
|
-
* name: "test"
|
|
1128
|
-
* });
|
|
1129
|
-
*
|
|
1130
|
-
* return (
|
|
1131
|
-
* <form onSubmit={handleSubmit(data => console.log(data))}>
|
|
1132
|
-
* {fields.map((item, index) => (
|
|
1133
|
-
* <input key={item.id} {...register(`test.${index}.firstName`)} />
|
|
1134
|
-
* ))}
|
|
1135
|
-
* <button type="button" onClick={() => append({ firstName: "bill" })}>
|
|
1136
|
-
* append
|
|
1137
|
-
* </button>
|
|
1138
|
-
* <input type="submit" />
|
|
1139
|
-
* </form>
|
|
1140
|
-
* );
|
|
1141
|
-
* }
|
|
1112
|
+
* const { fields, append } = useFieldArray({ control, name: "items" });
|
|
1113
|
+
* return fields.map((f, i) => <input key={f.id} {...register(`items.${i}.name`)} />);
|
|
1142
1114
|
* ```
|
|
1143
1115
|
*/
|
|
1144
1116
|
function useFieldArray(props) {
|
|
1145
1117
|
const formControl = useFormControlContext();
|
|
1146
1118
|
const { control = formControl, name, keyName = 'id', disabled, shouldUnregister, rules, } = props;
|
|
1147
|
-
const
|
|
1119
|
+
const getCurrentFieldArray = () => control._getFieldArray(name);
|
|
1120
|
+
const [fields, setFields] = React.useState(getCurrentFieldArray);
|
|
1148
1121
|
const ids = React.useRef(control._getFieldArray(name).map(generateId));
|
|
1149
1122
|
const _actioned = React.useRef(false);
|
|
1123
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect(getCurrentFieldArray);
|
|
1124
|
+
const _prevControl = React.useRef(control);
|
|
1125
|
+
const _prevName = React.useRef(name);
|
|
1150
1126
|
if (!disabled) {
|
|
1151
1127
|
control._names.array.add(name);
|
|
1152
1128
|
}
|
|
@@ -1158,7 +1134,23 @@ function useFieldArray(props) {
|
|
|
1158
1134
|
if (disabled) {
|
|
1159
1135
|
return;
|
|
1160
1136
|
}
|
|
1161
|
-
|
|
1137
|
+
if (_prevControl.current === control && _prevName.current === name) {
|
|
1138
|
+
resyncIfNeeded(true, getCurrentFieldArray, (fieldValues) => {
|
|
1139
|
+
setFields(fieldValues);
|
|
1140
|
+
ids.current = fieldValues.map(generateId);
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
else {
|
|
1144
|
+
_prevControl.current = control;
|
|
1145
|
+
_prevName.current = name;
|
|
1146
|
+
const fieldValues = getCurrentFieldArray();
|
|
1147
|
+
if (!deepEqual(fields, fieldValues)) {
|
|
1148
|
+
setFields(fieldValues);
|
|
1149
|
+
ids.current = fieldValues.map(generateId);
|
|
1150
|
+
}
|
|
1151
|
+
snapshot(true, getCurrentFieldArray);
|
|
1152
|
+
}
|
|
1153
|
+
const unsubscribe = control._subjects.array.subscribe({
|
|
1162
1154
|
next: ({ values, name: fieldArrayName, }) => {
|
|
1163
1155
|
if (fieldArrayName === name || !fieldArrayName) {
|
|
1164
1156
|
const fieldValues = get(values, name);
|
|
@@ -1173,7 +1165,11 @@ function useFieldArray(props) {
|
|
|
1173
1165
|
}
|
|
1174
1166
|
},
|
|
1175
1167
|
}).unsubscribe;
|
|
1176
|
-
|
|
1168
|
+
return () => {
|
|
1169
|
+
unsubscribe();
|
|
1170
|
+
snapshot(true, getCurrentFieldArray);
|
|
1171
|
+
};
|
|
1172
|
+
}, [control, name, disabled, resyncIfNeeded, snapshot]);
|
|
1177
1173
|
const updateValues = React.useCallback((updatedFieldArrayValues) => {
|
|
1178
1174
|
_actioned.current = true;
|
|
1179
1175
|
control._setFieldArray(name, updatedFieldArrayValues);
|
|
@@ -1285,7 +1281,9 @@ function useFieldArray(props) {
|
|
|
1285
1281
|
ids.current = updatedFieldArrayValues.map(generateId);
|
|
1286
1282
|
updateValues([...updatedFieldArrayValues]);
|
|
1287
1283
|
setFields([...updatedFieldArrayValues]);
|
|
1288
|
-
control._setFieldArray(name, [...updatedFieldArrayValues], (data) => data
|
|
1284
|
+
control._setFieldArray(name, [...updatedFieldArrayValues], (data) => Array.isArray(data)
|
|
1285
|
+
? data.slice(0, updatedFieldArrayValues.length)
|
|
1286
|
+
: data, {});
|
|
1289
1287
|
};
|
|
1290
1288
|
React.useEffect(() => {
|
|
1291
1289
|
if (disabled) {
|
|
@@ -1455,13 +1453,15 @@ const FieldArray = (props) => props.render(useFieldArray(props));
|
|
|
1455
1453
|
|
|
1456
1454
|
const isFileLike = (value) => (typeof Blob !== 'undefined' && value instanceof Blob) ||
|
|
1457
1455
|
(typeof File !== 'undefined' && value instanceof File);
|
|
1456
|
+
const isFileListLike = (value) => typeof FileList !== 'undefined' && value instanceof FileList;
|
|
1458
1457
|
const flatten = (obj) => {
|
|
1459
1458
|
const output = {};
|
|
1460
1459
|
for (const key of Object.keys(obj)) {
|
|
1461
1460
|
if (isObjectType(obj[key]) &&
|
|
1462
1461
|
obj[key] !== null &&
|
|
1463
1462
|
!isDateObject(obj[key]) &&
|
|
1464
|
-
!isFileLike(obj[key])
|
|
1463
|
+
!isFileLike(obj[key]) &&
|
|
1464
|
+
!isFileListLike(obj[key])) {
|
|
1465
1465
|
const nested = flatten(obj[key]);
|
|
1466
1466
|
for (const nestedKey of Object.keys(nested)) {
|
|
1467
1467
|
output[`${key}.${nestedKey}`] = nested[nestedKey];
|
|
@@ -1478,7 +1478,18 @@ function jsonToFormData(json) {
|
|
|
1478
1478
|
const result = new FormData();
|
|
1479
1479
|
const flattenFormValues = flatten(json);
|
|
1480
1480
|
for (const key in flattenFormValues) {
|
|
1481
|
-
|
|
1481
|
+
const value = flattenFormValues[key];
|
|
1482
|
+
if (isUndefined(value)) {
|
|
1483
|
+
continue;
|
|
1484
|
+
}
|
|
1485
|
+
if (typeof FileList !== 'undefined' && value instanceof FileList) {
|
|
1486
|
+
for (let index = 0; index < value.length; index++) {
|
|
1487
|
+
const file = value[index];
|
|
1488
|
+
file && result.append(key, file);
|
|
1489
|
+
}
|
|
1490
|
+
continue;
|
|
1491
|
+
}
|
|
1492
|
+
result.append(key, value);
|
|
1482
1493
|
}
|
|
1483
1494
|
return result;
|
|
1484
1495
|
}
|
|
@@ -1497,64 +1508,28 @@ function noop() { }
|
|
|
1497
1508
|
const HookFormContext = React.createContext(null);
|
|
1498
1509
|
HookFormContext.displayName = 'HookFormContext';
|
|
1499
1510
|
/**
|
|
1500
|
-
*
|
|
1501
|
-
*
|
|
1502
|
-
* @remarks
|
|
1503
|
-
* [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
|
1511
|
+
* Retrieves all `useForm` methods from the nearest `FormProvider`.
|
|
1512
|
+
* Use in deeply nested components to avoid prop-drilling.
|
|
1504
1513
|
*
|
|
1505
|
-
* @
|
|
1514
|
+
* @see [API](https://react-hook-form.com/docs/useformcontext)
|
|
1506
1515
|
*
|
|
1507
1516
|
* @example
|
|
1508
1517
|
* ```tsx
|
|
1509
|
-
*
|
|
1510
|
-
* const methods = useForm();
|
|
1511
|
-
* const onSubmit = data => console.log(data);
|
|
1512
|
-
*
|
|
1513
|
-
* return (
|
|
1514
|
-
* <FormProvider {...methods} >
|
|
1515
|
-
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
|
1516
|
-
* <NestedInput />
|
|
1517
|
-
* <input type="submit" />
|
|
1518
|
-
* </form>
|
|
1519
|
-
* </FormProvider>
|
|
1520
|
-
* );
|
|
1521
|
-
* }
|
|
1522
|
-
*
|
|
1523
|
-
* function NestedInput() {
|
|
1524
|
-
* const { register } = useFormContext(); // retrieve all hook methods
|
|
1525
|
-
* return <input {...register("test")} />;
|
|
1526
|
-
* }
|
|
1518
|
+
* const { register } = useFormContext<FormValues>();
|
|
1527
1519
|
* ```
|
|
1528
1520
|
*/
|
|
1529
1521
|
const useFormContext = () => React.useContext(HookFormContext);
|
|
1530
1522
|
/**
|
|
1531
|
-
*
|
|
1523
|
+
* Provides all `useForm` methods to the component tree via React Context.
|
|
1524
|
+
* Pair with `useFormContext` to consume them in any descendant.
|
|
1532
1525
|
*
|
|
1533
|
-
* @
|
|
1534
|
-
* [API](https://react-hook-form.com/docs/useformcontext) • [Demo](https://codesandbox.io/s/react-hook-form-v7-form-context-ytudi)
|
|
1535
|
-
*
|
|
1536
|
-
* @param props - all useForm methods
|
|
1526
|
+
* @see [API](https://react-hook-form.com/docs/useformcontext)
|
|
1537
1527
|
*
|
|
1538
1528
|
* @example
|
|
1539
1529
|
* ```tsx
|
|
1540
|
-
*
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
* return (
|
|
1545
|
-
* <FormProvider {...methods} >
|
|
1546
|
-
* <form onSubmit={methods.handleSubmit(onSubmit)}>
|
|
1547
|
-
* <NestedInput />
|
|
1548
|
-
* <input type="submit" />
|
|
1549
|
-
* </form>
|
|
1550
|
-
* </FormProvider>
|
|
1551
|
-
* );
|
|
1552
|
-
* }
|
|
1553
|
-
*
|
|
1554
|
-
* function NestedInput() {
|
|
1555
|
-
* const { register } = useFormContext(); // retrieve all hook methods
|
|
1556
|
-
* return <input {...register("test")} />;
|
|
1557
|
-
* }
|
|
1530
|
+
* <FormProvider {...methods}>
|
|
1531
|
+
* <form onSubmit={methods.handleSubmit(onSubmit)}>{children}</form>
|
|
1532
|
+
* </FormProvider>
|
|
1558
1533
|
* ```
|
|
1559
1534
|
*/
|
|
1560
1535
|
const FormProvider = ({ children, watch, getValues, getErrors, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, resetDefaultValues, handleSubmit, unregister, control, register, setFocus, subscribe, }) => {
|
|
@@ -1608,25 +1583,17 @@ function defaultValidateStatus(status) {
|
|
|
1608
1583
|
return status >= 200 && status < 300;
|
|
1609
1584
|
}
|
|
1610
1585
|
/**
|
|
1611
|
-
* Form component
|
|
1586
|
+
* Form component that handles submission, including optional `action` fetch and server error wiring.
|
|
1612
1587
|
*
|
|
1613
|
-
* @
|
|
1614
|
-
*
|
|
1615
|
-
* @returns form component or headless render prop.
|
|
1588
|
+
* @see [API](https://react-hook-form.com/docs/useform/form)
|
|
1616
1589
|
*
|
|
1617
1590
|
* @example
|
|
1618
1591
|
* ```tsx
|
|
1619
|
-
*
|
|
1620
|
-
*
|
|
1621
|
-
*
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1624
|
-
* <input {...register("name")} />
|
|
1625
|
-
* <p>{errors?.root?.server && 'Server error'}</p>
|
|
1626
|
-
* <button>Submit</button>
|
|
1627
|
-
* </Form>
|
|
1628
|
-
* );
|
|
1629
|
-
* }
|
|
1592
|
+
* <Form action="/api" control={control}>
|
|
1593
|
+
* <input {...register("name")} />
|
|
1594
|
+
* <p>{errors?.root?.server && 'Server error'}</p>
|
|
1595
|
+
* <button>Submit</button>
|
|
1596
|
+
* </Form>
|
|
1630
1597
|
* ```
|
|
1631
1598
|
*/
|
|
1632
1599
|
function Form(props) {
|
|
@@ -1984,7 +1951,7 @@ var hasValidation = (options) => options.mount &&
|
|
|
1984
1951
|
|
|
1985
1952
|
function schemaErrorLookup(errors, _fields, name) {
|
|
1986
1953
|
const error = get(errors, name);
|
|
1987
|
-
if (error ||
|
|
1954
|
+
if ((error === null || error === void 0 ? void 0 : error.type) || (error === null || error === void 0 ? void 0 : error.message) || Array.isArray(error)) {
|
|
1988
1955
|
return {
|
|
1989
1956
|
error,
|
|
1990
1957
|
name,
|
|
@@ -2138,24 +2105,35 @@ function createFormControl(props = {}) {
|
|
|
2138
2105
|
let _proxySubscribeFormState = {
|
|
2139
2106
|
..._proxyFormState,
|
|
2140
2107
|
};
|
|
2108
|
+
const _isTracked = (...keys) => keys.some((key) => _proxyFormState[key] || _proxySubscribeFormState[key]);
|
|
2141
2109
|
const _subjects = {
|
|
2142
2110
|
array: createSubject(),
|
|
2143
2111
|
state: createSubject(),
|
|
2144
2112
|
};
|
|
2145
2113
|
let _setValidCallId = 0;
|
|
2146
|
-
|
|
2114
|
+
let _resetCallId = 0;
|
|
2115
|
+
let shouldDisplayAllAssociatedErrors = _options.criteriaMode === VALIDATION_MODE.all;
|
|
2147
2116
|
const debounce = (name, callback) => (wait) => {
|
|
2148
2117
|
clearTimeout(timers[name]);
|
|
2149
2118
|
timers[name] = setTimeout(callback, wait);
|
|
2150
2119
|
};
|
|
2120
|
+
const cancelDelayedError = (name) => {
|
|
2121
|
+
clearTimeout(timers[name]);
|
|
2122
|
+
delete timers[name];
|
|
2123
|
+
delete delayErrorCallbacks[name];
|
|
2124
|
+
};
|
|
2125
|
+
const cancelDelayedErrorTree = (name) => {
|
|
2126
|
+
cancelDelayedError(name);
|
|
2127
|
+
const prefix = `${name}.`;
|
|
2128
|
+
for (const key of Object.keys(delayErrorCallbacks)) {
|
|
2129
|
+
key.startsWith(prefix) && cancelDelayedError(key);
|
|
2130
|
+
}
|
|
2131
|
+
};
|
|
2151
2132
|
const _setValid = async (shouldUpdateValid) => {
|
|
2152
2133
|
if (_state.keepIsValid) {
|
|
2153
2134
|
return;
|
|
2154
2135
|
}
|
|
2155
|
-
if (!_options.disabled &&
|
|
2156
|
-
(_proxyFormState.isValid ||
|
|
2157
|
-
_proxySubscribeFormState.isValid ||
|
|
2158
|
-
shouldUpdateValid)) {
|
|
2136
|
+
if (!_options.disabled && (_isTracked('isValid') || shouldUpdateValid)) {
|
|
2159
2137
|
const callId = ++_setValidCallId;
|
|
2160
2138
|
let isValid;
|
|
2161
2139
|
if (_options.resolver) {
|
|
@@ -2177,11 +2155,7 @@ function createFormControl(props = {}) {
|
|
|
2177
2155
|
}
|
|
2178
2156
|
};
|
|
2179
2157
|
const _updateIsValidating = (names, isValidating) => {
|
|
2180
|
-
if (!_options.disabled &&
|
|
2181
|
-
(_proxyFormState.isValidating ||
|
|
2182
|
-
_proxyFormState.validatingFields ||
|
|
2183
|
-
_proxySubscribeFormState.isValidating ||
|
|
2184
|
-
_proxySubscribeFormState.validatingFields)) {
|
|
2158
|
+
if (!_options.disabled && _isTracked('isValidating', 'validatingFields')) {
|
|
2185
2159
|
(names || _names.mount).forEach((name) => {
|
|
2186
2160
|
if (name) {
|
|
2187
2161
|
isValidating
|
|
@@ -2220,14 +2194,13 @@ function createFormControl(props = {}) {
|
|
|
2220
2194
|
unsetEmptyArray(_formState.errors, name);
|
|
2221
2195
|
}
|
|
2222
2196
|
const touchedFieldsArray = get(_formState.touchedFields, name);
|
|
2223
|
-
if ((
|
|
2224
|
-
_proxySubscribeFormState.touchedFields) &&
|
|
2197
|
+
if (_isTracked('touchedFields') &&
|
|
2225
2198
|
shouldUpdateFieldsAndState &&
|
|
2226
2199
|
Array.isArray(touchedFieldsArray)) {
|
|
2227
2200
|
const touchedFields = method(touchedFieldsArray, args.argA, args.argB);
|
|
2228
2201
|
shouldSetValues && set(_formState.touchedFields, name, touchedFields);
|
|
2229
2202
|
}
|
|
2230
|
-
if (
|
|
2203
|
+
if (_isTracked('dirtyFields')) {
|
|
2231
2204
|
_updateDirtyFields();
|
|
2232
2205
|
}
|
|
2233
2206
|
_subjects.state.next({
|
|
@@ -2250,6 +2223,7 @@ function createFormControl(props = {}) {
|
|
|
2250
2223
|
});
|
|
2251
2224
|
};
|
|
2252
2225
|
const _setErrors = (errors) => {
|
|
2226
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
2253
2227
|
_formState.errors = errors;
|
|
2254
2228
|
_subjects.state.next({
|
|
2255
2229
|
errors: _formState.errors,
|
|
@@ -2272,7 +2246,7 @@ function createFormControl(props = {}) {
|
|
|
2272
2246
|
}
|
|
2273
2247
|
return false;
|
|
2274
2248
|
};
|
|
2275
|
-
const
|
|
2249
|
+
const isStaleArrayField = (name) => {
|
|
2276
2250
|
if (!_state.actionArrayLengths.size) {
|
|
2277
2251
|
return false;
|
|
2278
2252
|
}
|
|
@@ -2299,13 +2273,19 @@ function createFormControl(props = {}) {
|
|
|
2299
2273
|
ownerPreActionLength = _state.actionArrayLengths.get(path);
|
|
2300
2274
|
}
|
|
2301
2275
|
node = node[key];
|
|
2276
|
+
if (isUndefined(node) &&
|
|
2277
|
+
ownerDepth !== -1 &&
|
|
2278
|
+
i > ownerDepth &&
|
|
2279
|
+
+segments[ownerDepth] < ownerPreActionLength) {
|
|
2280
|
+
return true;
|
|
2281
|
+
}
|
|
2302
2282
|
}
|
|
2303
2283
|
return false;
|
|
2304
2284
|
};
|
|
2305
2285
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
2306
2286
|
const field = get(_fields, name);
|
|
2307
2287
|
if (field) {
|
|
2308
|
-
if (hasExplicitNullIntermediate(name) ||
|
|
2288
|
+
if (hasExplicitNullIntermediate(name) || isStaleArrayField(name)) {
|
|
2309
2289
|
return;
|
|
2310
2290
|
}
|
|
2311
2291
|
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
@@ -2319,7 +2299,7 @@ function createFormControl(props = {}) {
|
|
|
2319
2299
|
_setValid();
|
|
2320
2300
|
if (wasUnsetInFormValues &&
|
|
2321
2301
|
_formState.isDirty &&
|
|
2322
|
-
(
|
|
2302
|
+
_isTracked('isDirty')) {
|
|
2323
2303
|
const isDirty = _getDirty();
|
|
2324
2304
|
if (!isDirty) {
|
|
2325
2305
|
_formState.isDirty = false;
|
|
@@ -2346,7 +2326,7 @@ function createFormControl(props = {}) {
|
|
|
2346
2326
|
if (!_options.disabled || shouldDirty === true) {
|
|
2347
2327
|
if (!isBlurEvent || shouldDirty) {
|
|
2348
2328
|
const isCurrentFieldPristine = deepEqual(get(_defaultValues, name), fieldValue);
|
|
2349
|
-
if (
|
|
2329
|
+
if (_isTracked('isDirty')) {
|
|
2350
2330
|
isPreviousDirty = _formState.isDirty;
|
|
2351
2331
|
_formState.isDirty = output.isDirty =
|
|
2352
2332
|
!isCurrentFieldPristine || _getDirty();
|
|
@@ -2364,8 +2344,7 @@ function createFormControl(props = {}) {
|
|
|
2364
2344
|
output.dirtyFields = _formState.dirtyFields;
|
|
2365
2345
|
shouldUpdateField =
|
|
2366
2346
|
shouldUpdateField ||
|
|
2367
|
-
((
|
|
2368
|
-
_proxySubscribeFormState.dirtyFields) &&
|
|
2347
|
+
(_isTracked('dirtyFields') &&
|
|
2369
2348
|
isPreviousDirty !== !isCurrentFieldPristine);
|
|
2370
2349
|
}
|
|
2371
2350
|
if (isBlurEvent) {
|
|
@@ -2375,8 +2354,7 @@ function createFormControl(props = {}) {
|
|
|
2375
2354
|
output.touchedFields = _formState.touchedFields;
|
|
2376
2355
|
shouldUpdateField =
|
|
2377
2356
|
shouldUpdateField ||
|
|
2378
|
-
((
|
|
2379
|
-
_proxySubscribeFormState.touchedFields) &&
|
|
2357
|
+
(_isTracked('touchedFields') &&
|
|
2380
2358
|
isPreviousFieldTouched !== isBlurEvent);
|
|
2381
2359
|
}
|
|
2382
2360
|
}
|
|
@@ -2386,7 +2364,7 @@ function createFormControl(props = {}) {
|
|
|
2386
2364
|
};
|
|
2387
2365
|
const shouldRenderByError = (name, isValid, error, fieldState) => {
|
|
2388
2366
|
const previousFieldError = get(_formState.errors, name);
|
|
2389
|
-
const shouldUpdateValid = (
|
|
2367
|
+
const shouldUpdateValid = _isTracked('isValid') &&
|
|
2390
2368
|
isBoolean(isValid) &&
|
|
2391
2369
|
_formState.isValid !== isValid;
|
|
2392
2370
|
if (_options.delayError && error) {
|
|
@@ -2394,8 +2372,7 @@ function createFormControl(props = {}) {
|
|
|
2394
2372
|
delayErrorCallbacks[name](_options.delayError);
|
|
2395
2373
|
}
|
|
2396
2374
|
else {
|
|
2397
|
-
|
|
2398
|
-
delete delayErrorCallbacks[name];
|
|
2375
|
+
cancelDelayedError(name);
|
|
2399
2376
|
error
|
|
2400
2377
|
? set(_formState.errors, name, error)
|
|
2401
2378
|
: unset(_formState.errors, name);
|
|
@@ -2418,22 +2395,34 @@ function createFormControl(props = {}) {
|
|
|
2418
2395
|
return await _options.resolver(_formValues, _options.context, getResolverOptions(name || _names.mount, _fields, _options.criteriaMode, _options.shouldUseNativeValidation));
|
|
2419
2396
|
};
|
|
2420
2397
|
const executeSchemaAndUpdateState = async (names) => {
|
|
2398
|
+
const resetCallId = _resetCallId;
|
|
2421
2399
|
const { errors } = await _runSchema(names);
|
|
2400
|
+
if (resetCallId !== _resetCallId) {
|
|
2401
|
+
return errors;
|
|
2402
|
+
}
|
|
2422
2403
|
_updateIsValidating(names);
|
|
2423
2404
|
if (names) {
|
|
2424
2405
|
for (const name of names) {
|
|
2425
2406
|
const error = get(errors, name);
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2407
|
+
cancelDelayedError(name);
|
|
2408
|
+
const isFieldArrayRootError = _names.array.has(name) &&
|
|
2409
|
+
isObject(error) &&
|
|
2410
|
+
!Object.keys(error).some((key) => !Number.isNaN(Number(key)));
|
|
2411
|
+
const field = get(_fields, name);
|
|
2412
|
+
const hasNestedFields = isObject(field) && Object.keys(field).some((key) => key !== '_f');
|
|
2413
|
+
isFieldArrayRootError
|
|
2414
|
+
? updateFieldArrayRootError(_formState.errors, { [name]: error }, name)
|
|
2415
|
+
: (error === null || error === void 0 ? void 0 : error.type) ||
|
|
2416
|
+
(error === null || error === void 0 ? void 0 : error.message) ||
|
|
2417
|
+
Array.isArray(error) ||
|
|
2418
|
+
(isObject(error) && hasNestedFields)
|
|
2419
|
+
? set(_formState.errors, name, error)
|
|
2420
|
+
: unset(_formState.errors, name);
|
|
2433
2421
|
}
|
|
2434
2422
|
_formState.errors = { ..._formState.errors };
|
|
2435
2423
|
}
|
|
2436
2424
|
else {
|
|
2425
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
2437
2426
|
_formState.errors = errors;
|
|
2438
2427
|
}
|
|
2439
2428
|
return errors;
|
|
@@ -2494,10 +2483,7 @@ function createFormControl(props = {}) {
|
|
|
2494
2483
|
if (_f) {
|
|
2495
2484
|
const isFieldArrayRoot = _names.array.has(_f.name);
|
|
2496
2485
|
const isPromiseFunction = field._f && hasPromiseValidation(field._f);
|
|
2497
|
-
const shouldTrackIsValidatingState =
|
|
2498
|
-
_proxyFormState.isValidating ||
|
|
2499
|
-
_proxySubscribeFormState.validatingFields ||
|
|
2500
|
-
_proxySubscribeFormState.isValidating;
|
|
2486
|
+
const shouldTrackIsValidatingState = _isTracked('isValidating', 'validatingFields');
|
|
2501
2487
|
if (isPromiseFunction && shouldTrackIsValidatingState) {
|
|
2502
2488
|
_updateIsValidating([_f.name], true);
|
|
2503
2489
|
}
|
|
@@ -2511,12 +2497,14 @@ function createFormControl(props = {}) {
|
|
|
2511
2497
|
break;
|
|
2512
2498
|
}
|
|
2513
2499
|
}
|
|
2514
|
-
!onlyCheckValid
|
|
2515
|
-
(
|
|
2500
|
+
if (!onlyCheckValid) {
|
|
2501
|
+
cancelDelayedError(_f.name);
|
|
2502
|
+
get(fieldError, _f.name)
|
|
2516
2503
|
? isFieldArrayRoot
|
|
2517
2504
|
? updateFieldArrayRootError(_formState.errors, fieldError, _f.name)
|
|
2518
2505
|
: set(_formState.errors, _f.name, fieldError[_f.name])
|
|
2519
|
-
: unset(_formState.errors, _f.name)
|
|
2506
|
+
: unset(_formState.errors, _f.name);
|
|
2507
|
+
}
|
|
2520
2508
|
if (props.shouldUseNativeValidation && fieldError[_f.name]) {
|
|
2521
2509
|
break;
|
|
2522
2510
|
}
|
|
@@ -2602,7 +2590,14 @@ function createFormControl(props = {}) {
|
|
|
2602
2590
|
}
|
|
2603
2591
|
}
|
|
2604
2592
|
(options.shouldDirty || options.shouldTouch) &&
|
|
2605
|
-
updateTouchAndDirty(name,
|
|
2593
|
+
updateTouchAndDirty(name, field &&
|
|
2594
|
+
field._f &&
|
|
2595
|
+
!field._f.disabled &&
|
|
2596
|
+
(field._f.valueAsNumber ||
|
|
2597
|
+
field._f.valueAsDate ||
|
|
2598
|
+
field._f.setValueAs)
|
|
2599
|
+
? getFieldValueAs(value, field._f)
|
|
2600
|
+
: fieldValue, options.shouldTouch, options.shouldDirty, !skipRender);
|
|
2606
2601
|
options.shouldValidate &&
|
|
2607
2602
|
trigger(name, {
|
|
2608
2603
|
delayError: options.delayError,
|
|
@@ -2617,7 +2612,7 @@ function createFormControl(props = {}) {
|
|
|
2617
2612
|
}
|
|
2618
2613
|
for (const fieldKey in value) {
|
|
2619
2614
|
if (!value.hasOwnProperty(fieldKey)) {
|
|
2620
|
-
|
|
2615
|
+
continue;
|
|
2621
2616
|
}
|
|
2622
2617
|
const fieldValue = value[fieldKey];
|
|
2623
2618
|
const fieldName = name + '.' + fieldKey;
|
|
@@ -2644,11 +2639,7 @@ function createFormControl(props = {}) {
|
|
|
2644
2639
|
name,
|
|
2645
2640
|
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
2646
2641
|
});
|
|
2647
|
-
if ((
|
|
2648
|
-
_proxyFormState.dirtyFields ||
|
|
2649
|
-
_proxySubscribeFormState.isDirty ||
|
|
2650
|
-
_proxySubscribeFormState.dirtyFields) &&
|
|
2651
|
-
options.shouldDirty) {
|
|
2642
|
+
if (_isTracked('isDirty', 'dirtyFields') && options.shouldDirty) {
|
|
2652
2643
|
_updateDirtyFields();
|
|
2653
2644
|
if (!skipStateEmit) {
|
|
2654
2645
|
_subjects.state.next({
|
|
@@ -2738,7 +2729,7 @@ function createFormControl(props = {}) {
|
|
|
2738
2729
|
const shouldSkipValidation = hasNoValidationEffect ||
|
|
2739
2730
|
skipValidation(isBlurEvent, get(_formState.touchedFields, name), _formState.isSubmitted, _validationModeAfterSubmit, _validationModeBeforeSubmit);
|
|
2740
2731
|
const watched = isWatched(name, _names, isBlurEvent);
|
|
2741
|
-
set(_formValues, name, fieldValue);
|
|
2732
|
+
set(_formValues, name, cloneObject(fieldValue));
|
|
2742
2733
|
if (isBlurEvent) {
|
|
2743
2734
|
if (!target || !target.readOnly) {
|
|
2744
2735
|
field._f.onBlur && field._f.onBlur(event);
|
|
@@ -2761,7 +2752,7 @@ function createFormControl(props = {}) {
|
|
|
2761
2752
|
});
|
|
2762
2753
|
if (shouldSkipValidation) {
|
|
2763
2754
|
if ((!hasNoValidationEffect || !_formState.isValid) &&
|
|
2764
|
-
(
|
|
2755
|
+
_isTracked('isValid')) {
|
|
2765
2756
|
if (_options.mode === 'onBlur') {
|
|
2766
2757
|
if (isBlurEvent) {
|
|
2767
2758
|
_setValid();
|
|
@@ -2804,8 +2795,7 @@ function createFormControl(props = {}) {
|
|
|
2804
2795
|
if (error) {
|
|
2805
2796
|
isValid = false;
|
|
2806
2797
|
}
|
|
2807
|
-
else if (
|
|
2808
|
-
_proxySubscribeFormState.isValid) {
|
|
2798
|
+
else if (_isTracked('isValid')) {
|
|
2809
2799
|
isValid = await executeBuiltInValidation({
|
|
2810
2800
|
fields: _fields,
|
|
2811
2801
|
onlyCheckValid: true,
|
|
@@ -2835,11 +2825,15 @@ function createFormControl(props = {}) {
|
|
|
2835
2825
|
let validationResult;
|
|
2836
2826
|
const fieldNames = convertToArrayPayload(name);
|
|
2837
2827
|
if (_options.resolver) {
|
|
2828
|
+
const resetCallId = _resetCallId;
|
|
2838
2829
|
const errors = await executeSchemaAndUpdateState(isUndefined(name) ? name : fieldNames);
|
|
2839
2830
|
isValid = isEmptyObject(errors);
|
|
2840
2831
|
validationResult = name
|
|
2841
2832
|
? !fieldNames.some((name) => get(errors, name))
|
|
2842
2833
|
: isValid;
|
|
2834
|
+
if (resetCallId !== _resetCallId) {
|
|
2835
|
+
return validationResult;
|
|
2836
|
+
}
|
|
2843
2837
|
}
|
|
2844
2838
|
else if (name) {
|
|
2845
2839
|
validationResult = (await Promise.all(fieldNames.map(async (fieldName) => {
|
|
@@ -2866,17 +2860,24 @@ function createFormControl(props = {}) {
|
|
|
2866
2860
|
delayErrorCallbacks[name](_options.delayError);
|
|
2867
2861
|
}
|
|
2868
2862
|
else {
|
|
2869
|
-
|
|
2870
|
-
|
|
2863
|
+
cancelDelayedError(name);
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
if (options.shouldTouch) {
|
|
2867
|
+
for (const fieldName of name ? fieldNames : _names.mount) {
|
|
2868
|
+
!_names.array.has(fieldName) &&
|
|
2869
|
+
set(_formState.touchedFields, fieldName, true);
|
|
2871
2870
|
}
|
|
2872
2871
|
}
|
|
2873
2872
|
_subjects.state.next({
|
|
2874
2873
|
...(!isString(name) ||
|
|
2875
|
-
((
|
|
2876
|
-
isValid !== _formState.isValid)
|
|
2874
|
+
(_isTracked('isValid') && isValid !== _formState.isValid)
|
|
2877
2875
|
? {}
|
|
2878
2876
|
: { name }),
|
|
2879
2877
|
...(_options.resolver || !name ? { isValid } : {}),
|
|
2878
|
+
...(options.shouldTouch && _isTracked('touchedFields')
|
|
2879
|
+
? { touchedFields: _formState.touchedFields }
|
|
2880
|
+
: {}),
|
|
2880
2881
|
errors: _formState.errors,
|
|
2881
2882
|
});
|
|
2882
2883
|
options.shouldFocus &&
|
|
@@ -2909,15 +2910,16 @@ function createFormControl(props = {}) {
|
|
|
2909
2910
|
invalid: !!error,
|
|
2910
2911
|
isDirty: !!get(targetFormState.dirtyFields, name),
|
|
2911
2912
|
error,
|
|
2912
|
-
isValidating: !!get(
|
|
2913
|
+
isValidating: !!get(targetFormState.validatingFields, name),
|
|
2913
2914
|
isTouched: !!get(targetFormState.touchedFields, name),
|
|
2914
2915
|
};
|
|
2915
2916
|
};
|
|
2916
2917
|
const clearErrors = (name) => {
|
|
2917
2918
|
const names = name ? convertToArrayPayload(name) : undefined;
|
|
2918
|
-
names === null || names === void 0 ? void 0 : names.forEach((inputName) => unset(_formState.errors, inputName));
|
|
2919
2919
|
if (names) {
|
|
2920
2920
|
names.forEach((inputName) => {
|
|
2921
|
+
cancelDelayedErrorTree(inputName);
|
|
2922
|
+
unset(_formState.errors, inputName);
|
|
2921
2923
|
_subjects.state.next({
|
|
2922
2924
|
name: inputName,
|
|
2923
2925
|
errors: _formState.errors,
|
|
@@ -2925,6 +2927,7 @@ function createFormControl(props = {}) {
|
|
|
2925
2927
|
});
|
|
2926
2928
|
}
|
|
2927
2929
|
else {
|
|
2930
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
2928
2931
|
_formState.errors = {};
|
|
2929
2932
|
_subjects.state.next({
|
|
2930
2933
|
errors: _formState.errors,
|
|
@@ -2932,9 +2935,10 @@ function createFormControl(props = {}) {
|
|
|
2932
2935
|
}
|
|
2933
2936
|
};
|
|
2934
2937
|
const setError = (name, error, options) => {
|
|
2938
|
+
cancelDelayedError(name);
|
|
2935
2939
|
const ref = (get(_fields, name, { _f: {} })._f || {}).ref;
|
|
2936
2940
|
const currentError = get(_formState.errors, name) || {};
|
|
2937
|
-
const { ref: currentRef, message, type, ...restOfErrorTree } = currentError;
|
|
2941
|
+
const { ref: currentRef, message, type, types, ...restOfErrorTree } = currentError;
|
|
2938
2942
|
set(_formState.errors, name, {
|
|
2939
2943
|
...restOfErrorTree,
|
|
2940
2944
|
...error,
|
|
@@ -3019,11 +3023,15 @@ function createFormControl(props = {}) {
|
|
|
3019
3023
|
for (const fieldName of name ? convertToArrayPayload(name) : _names.mount) {
|
|
3020
3024
|
_names.mount.delete(fieldName);
|
|
3021
3025
|
_names.array.delete(fieldName);
|
|
3026
|
+
_names.disabled.delete(fieldName);
|
|
3022
3027
|
if (!options.keepValue) {
|
|
3023
3028
|
unset(_fields, fieldName);
|
|
3024
3029
|
unset(_formValues, fieldName);
|
|
3025
3030
|
}
|
|
3026
|
-
!options.keepError
|
|
3031
|
+
if (!options.keepError) {
|
|
3032
|
+
cancelDelayedErrorTree(fieldName);
|
|
3033
|
+
unset(_formState.errors, fieldName);
|
|
3034
|
+
}
|
|
3027
3035
|
!options.keepDirty && unset(_formState.dirtyFields, fieldName);
|
|
3028
3036
|
!options.keepTouched && unset(_formState.touchedFields, fieldName);
|
|
3029
3037
|
!options.keepIsValidating &&
|
|
@@ -3039,6 +3047,9 @@ function createFormControl(props = {}) {
|
|
|
3039
3047
|
_subjects.state.next({
|
|
3040
3048
|
..._formState,
|
|
3041
3049
|
...(options.keepDirty ? {} : { isDirty: _getDirty() }),
|
|
3050
|
+
...(options.keepIsValidating
|
|
3051
|
+
? {}
|
|
3052
|
+
: { isValidating: !isEmptyObject(_formState.validatingFields) }),
|
|
3042
3053
|
});
|
|
3043
3054
|
!options.keepIsValid && _setValid();
|
|
3044
3055
|
};
|
|
@@ -3161,7 +3172,7 @@ function createFormControl(props = {}) {
|
|
|
3161
3172
|
});
|
|
3162
3173
|
}
|
|
3163
3174
|
}
|
|
3164
|
-
}, 0
|
|
3175
|
+
}, 0);
|
|
3165
3176
|
}
|
|
3166
3177
|
};
|
|
3167
3178
|
const handleSubmit = (onValid, onInvalid) => async (e) => {
|
|
@@ -3177,8 +3188,13 @@ function createFormControl(props = {}) {
|
|
|
3177
3188
|
isSubmitting: true,
|
|
3178
3189
|
});
|
|
3179
3190
|
if (_options.resolver) {
|
|
3191
|
+
const resetCallId = _resetCallId;
|
|
3180
3192
|
const { errors, values } = await _runSchema();
|
|
3193
|
+
if (resetCallId !== _resetCallId) {
|
|
3194
|
+
return;
|
|
3195
|
+
}
|
|
3181
3196
|
_updateIsValidating();
|
|
3197
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
3182
3198
|
_formState.errors = errors;
|
|
3183
3199
|
fieldValues = cloneObject(values);
|
|
3184
3200
|
}
|
|
@@ -3187,13 +3203,13 @@ function createFormControl(props = {}) {
|
|
|
3187
3203
|
fields: _fields,
|
|
3188
3204
|
eventType: EVENTS.SUBMIT,
|
|
3189
3205
|
});
|
|
3206
|
+
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
3190
3207
|
}
|
|
3191
3208
|
if (_names.disabled.size) {
|
|
3192
3209
|
for (const name of _names.disabled) {
|
|
3193
3210
|
unset(fieldValues, name);
|
|
3194
3211
|
}
|
|
3195
3212
|
}
|
|
3196
|
-
unset(_formState.errors, ROOT_ERROR_TYPE);
|
|
3197
3213
|
if (isEmptyObject(_formState.errors)) {
|
|
3198
3214
|
_subjects.state.next({
|
|
3199
3215
|
errors: {},
|
|
@@ -3226,6 +3242,7 @@ function createFormControl(props = {}) {
|
|
|
3226
3242
|
};
|
|
3227
3243
|
const resetField = (name, options = {}) => {
|
|
3228
3244
|
if (get(_fields, name)) {
|
|
3245
|
+
unset(_formState.validatingFields, name);
|
|
3229
3246
|
if (isUndefined(options.defaultValue)) {
|
|
3230
3247
|
setValue(name, cloneObject(get(_defaultValues, name)));
|
|
3231
3248
|
}
|
|
@@ -3243,18 +3260,24 @@ function createFormControl(props = {}) {
|
|
|
3243
3260
|
: _getDirty();
|
|
3244
3261
|
}
|
|
3245
3262
|
if (!options.keepError) {
|
|
3263
|
+
cancelDelayedError(name);
|
|
3246
3264
|
unset(_formState.errors, name);
|
|
3247
|
-
|
|
3265
|
+
_setValid();
|
|
3248
3266
|
}
|
|
3249
|
-
_subjects.state.next({
|
|
3267
|
+
_subjects.state.next({
|
|
3268
|
+
..._formState,
|
|
3269
|
+
isValidating: !isEmptyObject(_formState.validatingFields),
|
|
3270
|
+
});
|
|
3250
3271
|
}
|
|
3251
3272
|
};
|
|
3252
3273
|
const _reset = (formValues, keepStateOptions = {}) => {
|
|
3274
|
+
_resetCallId++;
|
|
3253
3275
|
const updatedValues = formValues ? cloneObject(formValues) : _defaultValues;
|
|
3254
3276
|
const cloneUpdatedValues = cloneObject(updatedValues);
|
|
3255
3277
|
const isEmptyResetValues = isEmptyObject(formValues);
|
|
3256
3278
|
const values = cloneUpdatedValues;
|
|
3257
3279
|
const fieldRefs = _fields;
|
|
3280
|
+
Object.keys(delayErrorCallbacks).forEach(cancelDelayedError);
|
|
3258
3281
|
if (!keepStateOptions.keepDefaultValues) {
|
|
3259
3282
|
_defaultValues = updatedValues;
|
|
3260
3283
|
}
|
|
@@ -3372,10 +3395,16 @@ function createFormControl(props = {}) {
|
|
|
3372
3395
|
? getDirtyFields(_defaultValues, formValues, undefined, fieldRefs)
|
|
3373
3396
|
: keepStateOptions.keepDirty
|
|
3374
3397
|
? _formState.dirtyFields
|
|
3375
|
-
:
|
|
3398
|
+
: keepStateOptions.keepValues
|
|
3399
|
+
? getDirtyFields(_defaultValues, _formValues, undefined, fieldRefs)
|
|
3400
|
+
: {},
|
|
3376
3401
|
touchedFields: keepStateOptions.keepTouched
|
|
3377
3402
|
? _formState.touchedFields
|
|
3378
3403
|
: {},
|
|
3404
|
+
...(!keepStateOptions.keepIsValidating &&
|
|
3405
|
+
(_formState.isValidating || !isEmptyObject(_formState.validatingFields))
|
|
3406
|
+
? { validatingFields: {}, isValidating: false }
|
|
3407
|
+
: null),
|
|
3379
3408
|
errors: keepStateOptions.keepErrors ? _formState.errors : {},
|
|
3380
3409
|
isSubmitSuccessful: keepStateOptions.keepIsSubmitSuccessful
|
|
3381
3410
|
? _formState.isSubmitSuccessful
|
|
@@ -3497,6 +3526,8 @@ function createFormControl(props = {}) {
|
|
|
3497
3526
|
};
|
|
3498
3527
|
_validationModeBeforeSubmit = getValidationModes(_options.mode);
|
|
3499
3528
|
_validationModeAfterSubmit = getValidationModes(_options.reValidateMode);
|
|
3529
|
+
shouldDisplayAllAssociatedErrors =
|
|
3530
|
+
_options.criteriaMode === VALIDATION_MODE.all;
|
|
3500
3531
|
},
|
|
3501
3532
|
},
|
|
3502
3533
|
subscribe,
|
|
@@ -3524,32 +3555,17 @@ function createFormControl(props = {}) {
|
|
|
3524
3555
|
}
|
|
3525
3556
|
|
|
3526
3557
|
/**
|
|
3527
|
-
*
|
|
3528
|
-
*
|
|
3529
|
-
* @remarks
|
|
3530
|
-
* [API](https://react-hook-form.com/docs/useform) • [Demo](https://codesandbox.io/s/react-hook-form-get-started-ts-5ksmm) • [Video](https://www.youtube.com/watch?v=RkXv4AXXC_4)
|
|
3558
|
+
* Core hook for managing a form. Returns all methods and state for
|
|
3559
|
+
* registration, validation, and submission.
|
|
3531
3560
|
*
|
|
3532
|
-
* @
|
|
3533
|
-
*
|
|
3534
|
-
* @returns methods - individual functions to manage the form state. {@link UseFormReturn}
|
|
3561
|
+
* @see [API](https://react-hook-form.com/docs/useform)
|
|
3535
3562
|
*
|
|
3536
3563
|
* @example
|
|
3537
3564
|
* ```tsx
|
|
3538
|
-
*
|
|
3539
|
-
*
|
|
3540
|
-
*
|
|
3541
|
-
*
|
|
3542
|
-
* console.log(watch("example"));
|
|
3543
|
-
*
|
|
3544
|
-
* return (
|
|
3545
|
-
* <form onSubmit={handleSubmit(onSubmit)}>
|
|
3546
|
-
* <input defaultValue="test" {...register("example")} />
|
|
3547
|
-
* <input {...register("exampleRequired", { required: true })} />
|
|
3548
|
-
* {errors.exampleRequired && <span>This field is required</span>}
|
|
3549
|
-
* <button>Submit</button>
|
|
3550
|
-
* </form>
|
|
3551
|
-
* );
|
|
3552
|
-
* }
|
|
3565
|
+
* const { register, handleSubmit, formState: { errors } } = useForm<FormValues>();
|
|
3566
|
+
* <form onSubmit={handleSubmit(onSubmit)}>
|
|
3567
|
+
* <input {...register("email", { required: true })} />
|
|
3568
|
+
* </form>
|
|
3553
3569
|
* ```
|
|
3554
3570
|
*/
|
|
3555
3571
|
function useForm(props = {}) {
|
|
@@ -3587,12 +3603,12 @@ function useForm(props = {}) {
|
|
|
3587
3603
|
}
|
|
3588
3604
|
const control = _formControl.current.control;
|
|
3589
3605
|
control._options = props;
|
|
3590
|
-
const
|
|
3606
|
+
const getCurrentFormState = () => ({
|
|
3607
|
+
...control._formState,
|
|
3608
|
+
defaultValues: control._defaultValues,
|
|
3609
|
+
});
|
|
3610
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect(getCurrentFormState);
|
|
3591
3611
|
useIsomorphicLayoutEffect(() => {
|
|
3592
|
-
const getCurrentFormState = () => ({
|
|
3593
|
-
...control._formState,
|
|
3594
|
-
defaultValues: control._defaultValues,
|
|
3595
|
-
});
|
|
3596
3612
|
resyncIfNeeded(true, getCurrentFormState, updateFormState);
|
|
3597
3613
|
const unsubscribe = control._subscribe({
|
|
3598
3614
|
formState: control._proxyFormState,
|
|
@@ -3676,32 +3692,20 @@ function useForm(props = {}) {
|
|
|
3676
3692
|
}
|
|
3677
3693
|
|
|
3678
3694
|
/**
|
|
3679
|
-
*
|
|
3695
|
+
* Component wrapper around `useWatch`. Re-renders only when watched fields change.
|
|
3680
3696
|
*
|
|
3681
|
-
* @
|
|
3682
|
-
* @param name - Can be field name, array of field names, or undefined to watch the entire form
|
|
3683
|
-
* @param disabled - Disable subscription
|
|
3684
|
-
* @param exact - Whether to watch exact field names or not
|
|
3685
|
-
* @param defaultValue - The default value to use if the field is not yet set
|
|
3686
|
-
* @param compute - Function to compute derived values from watched fields
|
|
3687
|
-
* @param render - The function that receives watched values and returns ReactNode
|
|
3688
|
-
* @returns The result of calling render function with watched values
|
|
3697
|
+
* @see [API](https://react-hook-form.com/docs/usewatch)
|
|
3689
3698
|
*
|
|
3690
3699
|
* @example
|
|
3691
|
-
* The `Watch` component only re-render when the values of `foo`, `bar`, and `baz.qux` change.
|
|
3692
|
-
* The types of `foo`, `bar`, and `baz.qux` are precisely inferred.
|
|
3693
|
-
*
|
|
3694
3700
|
* ```tsx
|
|
3695
|
-
* const { control } = useForm();
|
|
3696
|
-
*
|
|
3697
3701
|
* <Watch
|
|
3698
3702
|
* control={control}
|
|
3699
|
-
* names={[
|
|
3700
|
-
* render={([foo, bar
|
|
3703
|
+
* names={["foo", "bar"]}
|
|
3704
|
+
* render={([foo, bar]) => <span>{foo} {bar}</span>}
|
|
3701
3705
|
* />
|
|
3702
3706
|
* ```
|
|
3703
3707
|
*/
|
|
3704
3708
|
const Watch = (props) => props.render(useWatch({ name: props.names, ...props }));
|
|
3705
3709
|
|
|
3706
|
-
export { Controller, FieldArray, Form, FormProvider, FormState, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
|
|
3710
|
+
export { Controller, ErrorMessage, FieldArray, Form, FormProvider, FormState, FormStateSubscribe, Watch, appendErrors, createFormControl, get, set, useController, useFieldArray, useForm, useFormContext, useFormState, useWatch };
|
|
3707
3711
|
//# sourceMappingURL=index.esm.mjs.map
|