react-hook-form 7.55.0-next.9 → 7.56.0-next.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.
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useRef, useEffect } from 'react';
2
2
 
3
3
  var isCheckBoxInput = (element) => element.type === 'checkbox';
4
4
 
@@ -216,6 +216,48 @@ var getProxyFormState = (formState, control, localProxyFormState, isRoot = true)
216
216
  return result;
217
217
  };
218
218
 
219
+ var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
220
+
221
+ function deepEqual(object1, object2) {
222
+ if (isPrimitive(object1) || isPrimitive(object2)) {
223
+ return object1 === object2;
224
+ }
225
+ if (isDateObject(object1) && isDateObject(object2)) {
226
+ return object1.getTime() === object2.getTime();
227
+ }
228
+ const keys1 = Object.keys(object1);
229
+ const keys2 = Object.keys(object2);
230
+ if (keys1.length !== keys2.length) {
231
+ return false;
232
+ }
233
+ for (const key of keys1) {
234
+ const val1 = object1[key];
235
+ if (!keys2.includes(key)) {
236
+ return false;
237
+ }
238
+ if (key !== 'ref') {
239
+ const val2 = object2[key];
240
+ if ((isDateObject(val1) && isDateObject(val2)) ||
241
+ (isObject(val1) && isObject(val2)) ||
242
+ (Array.isArray(val1) && Array.isArray(val2))
243
+ ? !deepEqual(val1, val2)
244
+ : val1 !== val2) {
245
+ return false;
246
+ }
247
+ }
248
+ }
249
+ return true;
250
+ }
251
+
252
+ const useDeepEqualEffect = (effect, deps) => {
253
+ const ref = useRef(deps);
254
+ if (!deepEqual(deps, ref.current)) {
255
+ ref.current = deps;
256
+ }
257
+ // eslint-disable-next-line react-hooks/exhaustive-deps
258
+ useEffect(effect, ref.current);
259
+ };
260
+
219
261
  /**
220
262
  * 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.
221
263
  *
@@ -260,10 +302,8 @@ function useFormState(props) {
260
302
  isValid: false,
261
303
  errors: false,
262
304
  });
263
- const _name = React.useRef(name);
264
- _name.current = name;
265
- React.useEffect(() => control._subscribe({
266
- name: _name.current,
305
+ useDeepEqualEffect(() => control._subscribe({
306
+ name: name,
267
307
  formState: _localProxyFormState.current,
268
308
  exact,
269
309
  callback: (formState) => {
@@ -273,7 +313,7 @@ function useFormState(props) {
273
313
  ...formState,
274
314
  });
275
315
  },
276
- }), [control, disabled, exact]);
316
+ }), [name, disabled, exact]);
277
317
  React.useEffect(() => {
278
318
  _localProxyFormState.current.isValid && control._setValid(true);
279
319
  }, [control]);
@@ -313,19 +353,16 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
313
353
  function useWatch(props) {
314
354
  const methods = useFormContext();
315
355
  const { control = methods.control, name, defaultValue, disabled, exact, } = props || {};
316
- const _name = React.useRef(name);
317
- const _defaultValue = React.useRef(defaultValue);
318
- _name.current = name;
319
- React.useEffect(() => control._subscribe({
320
- name: _name.current,
356
+ const [value, updateValue] = React.useState(control._getWatch(name, defaultValue));
357
+ useDeepEqualEffect(() => control._subscribe({
358
+ name: name,
321
359
  formState: {
322
360
  values: true,
323
361
  },
324
362
  exact,
325
363
  callback: (formState) => !disabled &&
326
- updateValue(generateWatchOutput(_name.current, control._names, formState.values || control._formValues, false, _defaultValue.current)),
327
- }), [control, disabled, exact]);
328
- const [value, updateValue] = React.useState(control._getWatch(name, defaultValue));
364
+ updateValue(generateWatchOutput(name, control._names, formState.values || control._formValues, false, defaultValue)),
365
+ }), [name, defaultValue, disabled, exact]);
329
366
  React.useEffect(() => control._removeUnmounted());
330
367
  return value;
331
368
  }
@@ -675,39 +712,6 @@ var createSubject = () => {
675
712
  };
676
713
  };
677
714
 
678
- var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
679
-
680
- function deepEqual(object1, object2) {
681
- if (isPrimitive(object1) || isPrimitive(object2)) {
682
- return object1 === object2;
683
- }
684
- if (isDateObject(object1) && isDateObject(object2)) {
685
- return object1.getTime() === object2.getTime();
686
- }
687
- const keys1 = Object.keys(object1);
688
- const keys2 = Object.keys(object2);
689
- if (keys1.length !== keys2.length) {
690
- return false;
691
- }
692
- for (const key of keys1) {
693
- const val1 = object1[key];
694
- if (!keys2.includes(key)) {
695
- return false;
696
- }
697
- if (key !== 'ref') {
698
- const val2 = object2[key];
699
- if ((isDateObject(val1) && isDateObject(val2)) ||
700
- (isObject(val1) && isObject(val2)) ||
701
- (Array.isArray(val1) && Array.isArray(val2))
702
- ? !deepEqual(val1, val2)
703
- : val1 !== val2) {
704
- return false;
705
- }
706
- }
707
- }
708
- return true;
709
- }
710
-
711
715
  var isEmptyObject = (value) => isObject(value) && !Object.keys(value).length;
712
716
 
713
717
  var isFileInput = (element) => element.type === 'file';
@@ -1256,6 +1260,7 @@ function createFormControl(props = {}) {
1256
1260
  let _formState = {
1257
1261
  submitCount: 0,
1258
1262
  isDirty: false,
1263
+ isReady: false,
1259
1264
  isLoading: isFunction(_options.defaultValues),
1260
1265
  isValidating: false,
1261
1266
  isSubmitted: false,
@@ -2581,6 +2586,7 @@ function useFieldArray(props) {
2581
2586
  };
2582
2587
  }
2583
2588
 
2589
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? React.useLayoutEffect : React.useEffect;
2584
2590
  /**
2585
2591
  * Custom hook to manage the entire form.
2586
2592
  *
@@ -2627,6 +2633,7 @@ function useForm(props = {}) {
2627
2633
  validatingFields: {},
2628
2634
  errors: props.errors || {},
2629
2635
  disabled: props.disabled || false,
2636
+ isReady: false,
2630
2637
  defaultValues: isFunction(props.defaultValues)
2631
2638
  ? undefined
2632
2639
  : props.defaultValues,
@@ -2644,12 +2651,36 @@ function useForm(props = {}) {
2644
2651
  }
2645
2652
  const control = _formControl.current.control;
2646
2653
  control._options = props;
2647
- React.useLayoutEffect(() => control._subscribe({
2648
- formState: control._proxyFormState,
2649
- callback: () => updateFormState({ ...control._formState }),
2650
- reRenderRoot: true,
2651
- }), [control]);
2654
+ useIsomorphicLayoutEffect(() => {
2655
+ const sub = control._subscribe({
2656
+ formState: control._proxyFormState,
2657
+ callback: () => updateFormState({ ...control._formState }),
2658
+ reRenderRoot: true,
2659
+ });
2660
+ updateFormState((data) => ({
2661
+ ...data,
2662
+ isReady: true,
2663
+ }));
2664
+ return sub;
2665
+ }, [control]);
2652
2666
  React.useEffect(() => control._disableForm(props.disabled), [control, props.disabled]);
2667
+ React.useEffect(() => {
2668
+ if (props.mode) {
2669
+ control._options.mode = props.mode;
2670
+ }
2671
+ if (props.reValidateMode) {
2672
+ control._options.reValidateMode = props.reValidateMode;
2673
+ }
2674
+ if (props.errors && !isEmptyObject(props.errors)) {
2675
+ control._setErrors(props.errors);
2676
+ }
2677
+ }, [control, props.errors, props.mode, props.reValidateMode]);
2678
+ React.useEffect(() => {
2679
+ props.shouldUnregister &&
2680
+ control._subjects.state.next({
2681
+ values: control._getWatch(),
2682
+ });
2683
+ }, [control, props.shouldUnregister]);
2653
2684
  React.useEffect(() => {
2654
2685
  if (control._proxyFormState.isDirty) {
2655
2686
  const isDirty = control._getDirty();
@@ -2669,12 +2700,7 @@ function useForm(props = {}) {
2669
2700
  else {
2670
2701
  control._resetDefaultValues();
2671
2702
  }
2672
- }, [props.values, control]);
2673
- React.useEffect(() => {
2674
- if (props.errors && !isEmptyObject(props.errors)) {
2675
- control._setErrors(props.errors);
2676
- }
2677
- }, [props.errors, control]);
2703
+ }, [control, props.values]);
2678
2704
  React.useEffect(() => {
2679
2705
  if (!control._state.mount) {
2680
2706
  control._setValid();
@@ -2686,12 +2712,6 @@ function useForm(props = {}) {
2686
2712
  }
2687
2713
  control._removeUnmounted();
2688
2714
  });
2689
- React.useEffect(() => {
2690
- props.shouldUnregister &&
2691
- control._subjects.state.next({
2692
- values: control._getWatch(),
2693
- });
2694
- }, [props.shouldUnregister, control]);
2695
2715
  _formControl.current.formState = getProxyFormState(formState, control);
2696
2716
  return _formControl.current;
2697
2717
  }