react-hook-form 7.11.2-beta.0 → 7.12.2

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/index.esm.js CHANGED
@@ -136,10 +136,10 @@ function useFormState(props) {
136
136
 
137
137
  function useController({ name, rules, defaultValue, control, shouldUnregister, }) {
138
138
  const methods = useFormContext();
139
- const { defaultValuesRef, register, fieldsRef, unregister, namesRef, subjectsRef, shouldUnmount, inFieldArrayActionRef, _formValues, } = control || methods.control;
140
- const fieldValue = get(_formValues.current, name);
141
- const [value, setInputStateValue] = React.useState(!isUndefined(fieldValue)
142
- ? fieldValue
139
+ const { defaultValuesRef, register, fieldsRef, unregister, namesRef, subjectsRef, shouldUnmount, inFieldArrayActionRef, } = control || methods.control;
140
+ const field = get(fieldsRef.current, name);
141
+ const [value, setInputStateValue] = React.useState(field && field._f && !isUndefined(field._f.value)
142
+ ? field._f.value
143
143
  : isUndefined(get(defaultValuesRef.current, name))
144
144
  ? defaultValue
145
145
  : get(defaultValuesRef.current, name));
@@ -148,11 +148,18 @@ function useController({ name, rules, defaultValue, control, shouldUnregister, }
148
148
  control: control || methods.control,
149
149
  name,
150
150
  });
151
+ function updateIsMounted(name, value) {
152
+ const field = get(fieldsRef.current, name);
153
+ if (field && field._f) {
154
+ field._f.mount = value;
155
+ }
156
+ }
151
157
  React.useEffect(() => {
152
158
  const controllerSubscription = subjectsRef.current.control.subscribe({
153
159
  next: (data) => (!data.name || name === data.name) &&
154
160
  setInputStateValue(get(data.values, name)),
155
161
  });
162
+ updateIsMounted(name, true);
156
163
  return () => {
157
164
  controllerSubscription.unsubscribe();
158
165
  const shouldUnmountField = shouldUnmount || shouldUnregister;
@@ -162,10 +169,7 @@ function useController({ name, rules, defaultValue, control, shouldUnregister, }
162
169
  unregister(name);
163
170
  }
164
171
  else {
165
- const field = get(fieldsRef.current, name);
166
- if (field && field._f) {
167
- field._f.mount = false;
168
- }
172
+ updateIsMounted(name, false);
169
173
  }
170
174
  };
171
175
  }, [name]);
@@ -263,6 +267,28 @@ const focusFieldBy = (fields, callback, fieldsNames) => {
263
267
  }
264
268
  };
265
269
 
270
+ const getFieldsValues = (fieldsRef, output = {}) => {
271
+ for (const name in fieldsRef.current) {
272
+ const field = fieldsRef.current[name];
273
+ if (field && !isNullOrUndefined(output)) {
274
+ const _f = field._f;
275
+ const current = omit(field, '_f');
276
+ set(output, name, _f && _f.ref
277
+ ? _f.ref.disabled || (_f.refs && _f.refs.every((ref) => ref.disabled))
278
+ ? undefined
279
+ : _f.value
280
+ : Array.isArray(field)
281
+ ? []
282
+ : {});
283
+ current &&
284
+ getFieldsValues({
285
+ current,
286
+ }, output[name]);
287
+ }
288
+ }
289
+ return output;
290
+ };
291
+
266
292
  var generateId = () => {
267
293
  const d = typeof performance === 'undefined' ? Date.now() : performance.now() * 1000;
268
294
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
@@ -275,29 +301,30 @@ var mapIds = (values = [], keyName) => values.map((value) => (Object.assign({ [k
275
301
 
276
302
  var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
277
303
 
278
- function deepEqual(object1, object2, isErrorObject) {
304
+ function deepEqual(object1, object2) {
279
305
  if (isPrimitive(object1) ||
280
306
  isPrimitive(object2) ||
281
307
  isDateObject(object1) ||
282
308
  isDateObject(object2)) {
283
309
  return object1 === object2;
284
310
  }
285
- if (!React.isValidElement(object1)) {
286
- const keys1 = Object.keys(object1);
287
- const keys2 = Object.keys(object2);
288
- if (keys1.length !== keys2.length) {
311
+ const keys1 = Object.keys(object1);
312
+ const keys2 = Object.keys(object2);
313
+ if (keys1.length !== keys2.length) {
314
+ return false;
315
+ }
316
+ for (const key of keys1) {
317
+ const val1 = object1[key];
318
+ if (!keys2.includes(key)) {
289
319
  return false;
290
320
  }
291
- for (const key of keys1) {
292
- const val1 = object1[key];
293
- if (!(isErrorObject && key === 'ref')) {
294
- const val2 = object2[key];
295
- if ((isObject(val1) || Array.isArray(val1)) &&
296
- (isObject(val2) || Array.isArray(val2))
297
- ? !deepEqual(val1, val2, isErrorObject)
298
- : val1 !== val2) {
299
- return false;
300
- }
321
+ if (key !== 'ref') {
322
+ const val2 = object2[key];
323
+ if ((isObject(val1) || Array.isArray(val1)) &&
324
+ (isObject(val2) || Array.isArray(val2))
325
+ ? !deepEqual(val1, val2)
326
+ : val1 !== val2) {
327
+ return false;
301
328
  }
302
329
  }
303
330
  }
@@ -348,7 +375,7 @@ function setDirtyFields(values, defaultValues, dirtyFields, parentNode, parentNa
348
375
  var setFieldArrayDirtyFields = (values, defaultValues, dirtyFields) => deepMerge(setDirtyFields(values, defaultValues, dirtyFields.slice(0, values.length)), setDirtyFields(defaultValues, values, dirtyFields.slice(0, values.length)));
349
376
 
350
377
  function append(data, value) {
351
- return [...data, ...convertToArrayPayload(value)];
378
+ return [...convertToArrayPayload(data), ...convertToArrayPayload(value)];
352
379
  }
353
380
 
354
381
  var fillEmptyArray = (value) => Array.isArray(value) ? Array(value.length).fill(undefined) : undefined;
@@ -373,7 +400,7 @@ var moveArrayAt = (data, from, to) => {
373
400
  };
374
401
 
375
402
  function prepend(data, value) {
376
- return [...convertToArrayPayload(value), ...data];
403
+ return [...convertToArrayPayload(value), ...convertToArrayPayload(data)];
377
404
  }
378
405
 
379
406
  function removeAtIndexes(data, indexes) {
@@ -438,9 +465,9 @@ const useFieldArray = ({ control, name, keyName = 'id', shouldUnregister, }) =>
438
465
  const methods = useFormContext();
439
466
  const focusNameRef = React.useRef('');
440
467
  const isMountedRef = React.useRef(false);
441
- const { getIsDirty, namesRef, fieldsRef, defaultValuesRef, formStateRef, subjectsRef, readFormStateRef, updateIsValid, fieldArrayDefaultValuesRef, unregister, shouldUnmount, inFieldArrayActionRef, setValues, register, _formValues, } = control || methods.control;
442
- const [fields, setFields] = React.useState(mapIds((get(_formValues.current, name) && isMountedRef.current
443
- ? get(_formValues.current, name)
468
+ const { getIsDirty, namesRef, fieldsRef, defaultValuesRef, formStateRef, subjectsRef, readFormStateRef, updateIsValid, fieldArrayDefaultValuesRef, unregister, shouldUnmount, inFieldArrayActionRef, setValues, register, } = control || methods.control;
469
+ const [fields, setFields] = React.useState(mapIds((get(fieldsRef.current, name) && isMountedRef.current
470
+ ? get(getFieldsValues(fieldsRef), name)
444
471
  : get(fieldArrayDefaultValuesRef.current, getNodeParentName(name))
445
472
  ? get(fieldArrayDefaultValuesRef.current, name)
446
473
  : get(defaultValuesRef.current, name)) || [], keyName));
@@ -448,7 +475,7 @@ const useFieldArray = ({ control, name, keyName = 'id', shouldUnregister, }) =>
448
475
  namesRef.current.array.add(name);
449
476
  const omitKey = (fields) => fields.map((field = {}) => omit(field, keyName));
450
477
  const getCurrentFieldsValues = () => {
451
- const values = get(_formValues.current, name, []);
478
+ const values = get(getFieldsValues(fieldsRef), name, []);
452
479
  return mapIds(get(fieldArrayDefaultValuesRef.current, name, []).map((item, index) => (Object.assign(Object.assign({}, item), values[index]))), keyName);
453
480
  };
454
481
  const getFocusFieldName = (index, options) => options && !options.shouldFocus
@@ -462,10 +489,6 @@ const useFieldArray = ({ control, name, keyName = 'id', shouldUnregister, }) =>
462
489
  const output = method(get(fieldsRef.current, name), args.argA, args.argB);
463
490
  shouldSet && set(fieldsRef.current, name, output);
464
491
  }
465
- if (get(_formValues.current, name)) {
466
- const output = method(get(_formValues.current, name), args.argA, args.argB);
467
- shouldSet && set(_formValues.current, name, output);
468
- }
469
492
  if (Array.isArray(get(formStateRef.current.errors, name))) {
470
493
  const output = method(get(formStateRef.current.errors, name), args.argA, args.argB);
471
494
  shouldSet && set(formStateRef.current.errors, name, output);
@@ -485,6 +508,8 @@ const useFieldArray = ({ control, name, keyName = 'id', shouldUnregister, }) =>
485
508
  cleanup(formStateRef.current.dirtyFields);
486
509
  }
487
510
  subjectsRef.current.state.next({
511
+ dirtyFields: formStateRef.current
512
+ .dirtyFields,
488
513
  isDirty: getIsDirty(name, omitKey(updatedFieldArrayValues)),
489
514
  errors: formStateRef.current.errors,
490
515
  isValid: formStateRef.current.isValid,
@@ -585,7 +610,7 @@ const useFieldArray = ({ control, name, keyName = 'id', shouldUnregister, }) =>
585
610
  }
586
611
  subjectsRef.current.watch.next({
587
612
  name,
588
- values: _formValues.current,
613
+ values: getFieldsValues(fieldsRef),
589
614
  });
590
615
  focusNameRef.current &&
591
616
  focusFieldBy(fieldsRef.current, (key) => key.startsWith(focusNameRef.current));
@@ -601,7 +626,6 @@ const useFieldArray = ({ control, name, keyName = 'id', shouldUnregister, }) =>
601
626
  next({ name: inputFieldArrayName, values, isReset }) {
602
627
  if (isReset) {
603
628
  unset(fieldsRef.current, inputFieldArrayName || name);
604
- unset(_formValues.current, inputFieldArrayName || name);
605
629
  inputFieldArrayName
606
630
  ? set(fieldArrayDefaultValuesRef.current, inputFieldArrayName, values)
607
631
  : (fieldArrayDefaultValuesRef.current = values);
@@ -609,7 +633,7 @@ const useFieldArray = ({ control, name, keyName = 'id', shouldUnregister, }) =>
609
633
  }
610
634
  },
611
635
  });
612
- !get(_formValues.current, name) && set(_formValues.current, name, []);
636
+ !get(fieldsRef.current, name) && set(fieldsRef.current, name, []);
613
637
  isMountedRef.current = true;
614
638
  return () => {
615
639
  fieldArraySubscription.unsubscribe();
@@ -618,7 +642,7 @@ const useFieldArray = ({ control, name, keyName = 'id', shouldUnregister, }) =>
618
642
  unset(fieldArrayDefaultValuesRef.current, name);
619
643
  }
620
644
  else {
621
- const fieldArrayValues = get(_formValues.current, name);
645
+ const fieldArrayValues = get(getFieldsValues(fieldsRef), name);
622
646
  fieldArrayValues &&
623
647
  set(fieldArrayDefaultValuesRef.current, name, fieldArrayValues);
624
648
  }
@@ -699,7 +723,7 @@ var getRadioValue = (options) => Array.isArray(options)
699
723
  function getFieldValue(field) {
700
724
  if (field && field._f) {
701
725
  const ref = field._f.ref;
702
- if (field._f.refs ? field._f.refs.every((ref) => ref.disabled) : ref.disabled) {
726
+ if (ref.disabled) {
703
727
  return;
704
728
  }
705
729
  if (isFileInput(ref)) {
@@ -785,8 +809,7 @@ var getValueAndMessage = (validationData) => isObject(validationData) && !isRege
785
809
  message: '',
786
810
  };
787
811
 
788
- var validateField = async (field, inputValue, validateAllFieldCriteria, shouldUseNativeValidation) => {
789
- const { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, valueAsNumber, mount, } = field._f;
812
+ var validateField = async ({ _f: { ref, refs, required, maxLength, minLength, min, max, pattern, validate, name, value: inputValue, valueAsNumber, mount, }, }, validateAllFieldCriteria, shouldUseNativeValidation) => {
790
813
  if (!mount) {
791
814
  return {};
792
815
  }
@@ -922,6 +945,14 @@ var validateField = async (field, inputValue, validateAllFieldCriteria, shouldUs
922
945
  return error;
923
946
  };
924
947
 
948
+ var debounce = (callback, wait) => {
949
+ let timer = 0;
950
+ return (...args) => {
951
+ clearTimeout(timer);
952
+ timer = setTimeout(() => callback(...args), wait);
953
+ };
954
+ };
955
+
925
956
  var getValidationModes = (mode) => ({
926
957
  isOnSubmit: !mode || mode === VALIDATION_MODE.onSubmit,
927
958
  isOnBlur: mode === VALIDATION_MODE.onBlur,
@@ -981,7 +1012,7 @@ class Subject {
981
1012
  }
982
1013
 
983
1014
  const isWindowUndefined = typeof window === 'undefined';
984
- function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_MODE.onChange, resolver, context, defaultValues = {}, shouldFocusError = true, shouldUseNativeValidation, shouldUnregister, criteriaMode, } = {}) {
1015
+ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_MODE.onChange, resolver, context, defaultValues = {}, shouldFocusError = true, delayError, shouldUseNativeValidation, shouldUnregister, criteriaMode, } = {}) {
985
1016
  const [formState, updateFormState] = React.useState({
986
1017
  isDirty: false,
987
1018
  isValidating: false,
@@ -1005,12 +1036,12 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1005
1036
  const resolverRef = React.useRef(resolver);
1006
1037
  const formStateRef = React.useRef(formState);
1007
1038
  const fieldsRef = React.useRef({});
1008
- const _formValues = React.useRef({});
1009
1039
  const defaultValuesRef = React.useRef(defaultValues);
1010
1040
  const fieldArrayDefaultValuesRef = React.useRef({});
1011
1041
  const contextRef = React.useRef(context);
1012
1042
  const inFieldArrayActionRef = React.useRef(false);
1013
1043
  const isMountedRef = React.useRef(false);
1044
+ const _delayCallback = React.useRef();
1014
1045
  const subjectsRef = React.useRef({
1015
1046
  watch: new Subject(),
1016
1047
  control: new Subject(),
@@ -1031,22 +1062,44 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1031
1062
  const isFieldWatched = (name) => namesRef.current.watchAll ||
1032
1063
  namesRef.current.watch.has(name) ||
1033
1064
  namesRef.current.watch.has((name.match(/\w+/) || [])[0]);
1034
- const shouldRenderBaseOnError = React.useCallback(async (shouldSkipRender, name, error, inputState, isValidFromResolver, isWatched) => {
1065
+ const updateErrorState = (name, error) => {
1066
+ set(formStateRef.current.errors, name, error);
1067
+ subjectsRef.current.state.next({
1068
+ errors: formStateRef.current.errors,
1069
+ });
1070
+ };
1071
+ const shouldRenderBaseOnValid = async () => {
1072
+ const isValid = await validateForm(fieldsRef.current, true);
1073
+ if (isValid !== formStateRef.current.isValid) {
1074
+ formStateRef.current.isValid = isValid;
1075
+ subjectsRef.current.state.next({
1076
+ isValid,
1077
+ });
1078
+ }
1079
+ };
1080
+ const shouldRenderBaseOnError = React.useCallback(async (shouldSkipRender, name, error, fieldState, isValidFromResolver, isWatched) => {
1035
1081
  const previousError = get(formStateRef.current.errors, name);
1036
1082
  const isValid = readFormStateRef.current.isValid
1037
1083
  ? resolver
1038
1084
  ? isValidFromResolver
1039
- : await validateForm(fieldsRef.current, true)
1085
+ : shouldRenderBaseOnValid()
1040
1086
  : false;
1041
- error
1042
- ? set(formStateRef.current.errors, name, error)
1043
- : unset(formStateRef.current.errors, name);
1087
+ if (delayError && error) {
1088
+ _delayCallback.current =
1089
+ _delayCallback.current || debounce(updateErrorState, delayError);
1090
+ _delayCallback.current(name, error);
1091
+ }
1092
+ else {
1093
+ error
1094
+ ? set(formStateRef.current.errors, name, error)
1095
+ : unset(formStateRef.current.errors, name);
1096
+ }
1044
1097
  if ((isWatched ||
1045
- (error ? !deepEqual(previousError, error, true) : previousError) ||
1046
- !isEmptyObject(inputState) ||
1098
+ (error ? !deepEqual(previousError, error) : previousError) ||
1099
+ !isEmptyObject(fieldState) ||
1047
1100
  formStateRef.current.isValid !== isValid) &&
1048
1101
  !shouldSkipRender) {
1049
- const updatedFormState = Object.assign(Object.assign({}, inputState), { isValid: !!isValid, errors: formStateRef.current.errors, name });
1102
+ const updatedFormState = Object.assign(Object.assign(Object.assign({}, fieldState), (resolver ? { isValid: !!isValid } : {})), { errors: formStateRef.current.errors, name });
1050
1103
  formStateRef.current = Object.assign(Object.assign({}, formStateRef.current), updatedFormState);
1051
1104
  subjectsRef.current.state.next(isWatched ? { name } : updatedFormState);
1052
1105
  }
@@ -1063,8 +1116,7 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1063
1116
  const value = isWeb && isHTMLElement(_f.ref) && isNullOrUndefined(rawValue)
1064
1117
  ? ''
1065
1118
  : rawValue;
1066
- const fieldValue = getFieldValueAs(rawValue, _f);
1067
- _f.value = fieldValue;
1119
+ _f.value = getFieldValueAs(rawValue, _f);
1068
1120
  if (isRadioInput(_f.ref)) {
1069
1121
  (_f.refs || []).forEach((radioRef) => (radioRef.checked = radioRef.value === value));
1070
1122
  }
@@ -1084,10 +1136,11 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1084
1136
  else {
1085
1137
  _f.ref.value = value;
1086
1138
  }
1087
- set(_formValues.current, name, fieldValue);
1088
1139
  if (shouldRender) {
1140
+ const values = getFieldsValues(fieldsRef);
1141
+ set(values, name, rawValue);
1089
1142
  subjectsRef.current.control.next({
1090
- values: Object.assign(Object.assign({}, defaultValuesRef.current), getValues()),
1143
+ values: Object.assign(Object.assign({}, defaultValuesRef.current), values),
1091
1144
  name,
1092
1145
  });
1093
1146
  }
@@ -1103,13 +1156,13 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1103
1156
  },
1104
1157
  value: rawValue,
1105
1158
  };
1106
- set(_formValues.current, name, rawValue);
1107
1159
  }
1108
1160
  }
1109
1161
  }, []);
1110
1162
  const getIsDirty = React.useCallback((name, data) => {
1111
- name && data && set(_formValues.current, name, data);
1112
- return !deepEqual(Object.assign({}, getValues()), defaultValuesRef.current);
1163
+ const formValues = getFieldsValues(fieldsRef);
1164
+ name && data && set(formValues, name, data);
1165
+ return !deepEqual(formValues, defaultValuesRef.current);
1113
1166
  }, []);
1114
1167
  const updateTouchAndDirtyState = React.useCallback((name, inputValue, isCurrentTouched, shouldRender = true) => {
1115
1168
  const state = {
@@ -1146,12 +1199,12 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1146
1199
  return isChanged ? state : {};
1147
1200
  }, []);
1148
1201
  const executeInlineValidation = React.useCallback(async (name, skipReRender) => {
1149
- const error = (await validateField(get(fieldsRef.current, name), get(getValues(), name), isValidateAllFieldCriteria, shouldUseNativeValidation))[name];
1202
+ const error = (await validateField(get(fieldsRef.current, name), isValidateAllFieldCriteria, shouldUseNativeValidation))[name];
1150
1203
  await shouldRenderBaseOnError(skipReRender, name, error);
1151
1204
  return isUndefined(error);
1152
1205
  }, [isValidateAllFieldCriteria]);
1153
1206
  const executeResolverValidation = React.useCallback(async (names) => {
1154
- const { errors } = await resolverRef.current(getValues(), contextRef.current, getResolverOptions(namesRef.current.mount, fieldsRef.current, criteriaMode, shouldUseNativeValidation));
1207
+ const { errors } = await resolverRef.current(getFieldsValues(fieldsRef), contextRef.current, getResolverOptions(namesRef.current.mount, fieldsRef.current, criteriaMode, shouldUseNativeValidation));
1155
1208
  if (names) {
1156
1209
  for (const name of names) {
1157
1210
  const error = get(errors, name);
@@ -1174,7 +1227,7 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1174
1227
  const _f = field._f;
1175
1228
  const current = omit(field, '_f');
1176
1229
  if (_f) {
1177
- const fieldError = await validateField(field, get(getValues(), _f.name), isValidateAllFieldCriteria, shouldUseNativeValidation);
1230
+ const fieldError = await validateField(field, isValidateAllFieldCriteria, shouldUseNativeValidation);
1178
1231
  if (shouldCheckValid) {
1179
1232
  if (fieldError[_f.name]) {
1180
1233
  context.valid = false;
@@ -1222,38 +1275,42 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1222
1275
  readFormStateRef.current.isValid && updateIsValid();
1223
1276
  return isValid;
1224
1277
  }, [executeResolverValidation, executeInlineValidation]);
1225
- const updateIsValidAndInputValue = (name, ref) => {
1278
+ const updateIsValidAndInputValue = (name, ref, shouldSkipValueAs) => {
1226
1279
  const field = get(fieldsRef.current, name);
1227
- const fieldValue = get(getValues(), name);
1228
1280
  if (field) {
1229
- const isValueUndefined = isUndefined(fieldValue);
1281
+ const isValueUndefined = isUndefined(field._f.value);
1230
1282
  const defaultValue = isValueUndefined
1231
1283
  ? isUndefined(get(fieldArrayDefaultValuesRef.current, name))
1232
1284
  ? get(defaultValuesRef.current, name)
1233
1285
  : get(fieldArrayDefaultValuesRef.current, name)
1234
- : fieldValue;
1286
+ : field._f.value;
1235
1287
  if (!isUndefined(defaultValue)) {
1236
1288
  if (ref && ref.defaultChecked) {
1237
- set(_formValues.current, name, getFieldValue(field));
1289
+ field._f.value = getFieldValue(field);
1290
+ }
1291
+ else if (shouldSkipValueAs) {
1292
+ field._f.value = defaultValue;
1238
1293
  }
1239
1294
  else {
1240
1295
  setFieldValue(name, defaultValue);
1241
1296
  }
1242
1297
  }
1243
1298
  else if (isValueUndefined) {
1244
- set(_formValues.current, name, getFieldValue(field));
1299
+ field._f.value = getFieldValue(field);
1245
1300
  }
1246
1301
  }
1247
1302
  isMountedRef.current && readFormStateRef.current.isValid && updateIsValid();
1248
1303
  };
1249
- const updateIsValid = React.useCallback(async () => {
1304
+ const updateIsValid = React.useCallback(async (values = {}) => {
1250
1305
  const isValid = resolver
1251
- ? isEmptyObject((await resolverRef.current(getValues(), contextRef.current, getResolverOptions(namesRef.current.mount, fieldsRef.current, criteriaMode, shouldUseNativeValidation))).errors)
1306
+ ? isEmptyObject((await resolverRef.current(Object.assign(Object.assign({}, getFieldsValues(fieldsRef)), values), contextRef.current, getResolverOptions(namesRef.current.mount, fieldsRef.current, criteriaMode, shouldUseNativeValidation))).errors)
1252
1307
  : await validateForm(fieldsRef.current, true);
1253
- isValid !== formStateRef.current.isValid &&
1308
+ if (isValid !== formStateRef.current.isValid) {
1309
+ formStateRef.current.isValid = isValid;
1254
1310
  subjectsRef.current.state.next({
1255
1311
  isValid,
1256
1312
  });
1313
+ }
1257
1314
  }, [criteriaMode, shouldUseNativeValidation]);
1258
1315
  const setValues = React.useCallback((name, value, options) => Object.entries(value).forEach(([fieldKey, fieldValue]) => {
1259
1316
  const fieldName = `${name}.${fieldKey}`;
@@ -1284,21 +1341,45 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1284
1341
  });
1285
1342
  }
1286
1343
  !value.length &&
1344
+ set(fieldsRef.current, name, []) &&
1287
1345
  set(fieldArrayDefaultValuesRef.current, name, []);
1288
1346
  }
1289
- set(_formValues.current, name, value);
1290
1347
  ((field && !field._f) || isFieldArray) && !isNullOrUndefined(value)
1291
1348
  ? setValues(name, value, isFieldArray ? {} : options)
1292
1349
  : setFieldValue(name, value, options, true, !field);
1293
1350
  isFieldWatched(name) && subjectsRef.current.state.next({});
1294
- subjectsRef.current.watch.next({
1295
- name,
1296
- values: getValues(),
1297
- });
1351
+ subjectsRef.current.watch.next({ name, values: getValues() });
1298
1352
  };
1299
- const handleChange = React.useCallback(async ({ type, target, target: { value, name, type: inputType } }) => {
1353
+ const handleValidate = async (target, fieldState, isWatched, isBlurEvent) => {
1300
1354
  let error;
1301
1355
  let isValid;
1356
+ let name = target.name;
1357
+ const field = get(fieldsRef.current, name);
1358
+ if (resolver) {
1359
+ const { errors } = await resolverRef.current(getFieldsValues(fieldsRef), contextRef.current, getResolverOptions([name], fieldsRef.current, criteriaMode, shouldUseNativeValidation));
1360
+ error = get(errors, name);
1361
+ if (isCheckBoxInput(target) && !error) {
1362
+ const parentNodeName = getNodeParentName(name);
1363
+ const currentError = get(errors, parentNodeName, {});
1364
+ currentError.type && currentError.message && (error = currentError);
1365
+ if (currentError || get(formStateRef.current.errors, parentNodeName)) {
1366
+ name = parentNodeName;
1367
+ }
1368
+ }
1369
+ isValid = isEmptyObject(errors);
1370
+ }
1371
+ else {
1372
+ error = (await validateField(field, isValidateAllFieldCriteria, shouldUseNativeValidation))[name];
1373
+ }
1374
+ !isBlurEvent &&
1375
+ subjectsRef.current.watch.next({
1376
+ name,
1377
+ type: target.type,
1378
+ values: getValues(),
1379
+ });
1380
+ shouldRenderBaseOnError(false, name, error, fieldState, isValid, isWatched);
1381
+ };
1382
+ const handleChange = React.useCallback(async ({ type, target, target: { value, name, type: inputType } }) => {
1302
1383
  const field = get(fieldsRef.current, name);
1303
1384
  if (field) {
1304
1385
  let inputValue = inputType ? getFieldValue(field) : undefined;
@@ -1312,10 +1393,10 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1312
1393
  isReValidateOnChange }, validationMode));
1313
1394
  const isWatched = !isBlurEvent && isFieldWatched(name);
1314
1395
  if (!isUndefined(inputValue)) {
1315
- set(_formValues.current, name, inputValue);
1396
+ field._f.value = inputValue;
1316
1397
  }
1317
- const inputState = updateTouchAndDirtyState(name, inputValue, isBlurEvent, false);
1318
- const shouldRender = !isEmptyObject(inputState) || isWatched;
1398
+ const fieldState = updateTouchAndDirtyState(name, field._f.value, isBlurEvent, false);
1399
+ const shouldRender = !isEmptyObject(fieldState) || isWatched;
1319
1400
  if (shouldSkipValidation) {
1320
1401
  !isBlurEvent &&
1321
1402
  subjectsRef.current.watch.next({
@@ -1324,39 +1405,16 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1324
1405
  values: getValues(),
1325
1406
  });
1326
1407
  return (shouldRender &&
1327
- subjectsRef.current.state.next(isWatched ? { name } : Object.assign(Object.assign({}, inputState), { name })));
1408
+ subjectsRef.current.state.next(isWatched ? { name } : Object.assign(Object.assign({}, fieldState), { name })));
1328
1409
  }
1329
1410
  subjectsRef.current.state.next({
1330
1411
  isValidating: true,
1331
1412
  });
1332
- if (resolver) {
1333
- const { errors } = await resolverRef.current(getValues(), contextRef.current, getResolverOptions([name], fieldsRef.current, criteriaMode, shouldUseNativeValidation));
1334
- error = get(errors, name);
1335
- if (isCheckBoxInput(target) && !error) {
1336
- const parentNodeName = getNodeParentName(name);
1337
- const currentError = get(errors, parentNodeName, {});
1338
- currentError.type && currentError.message && (error = currentError);
1339
- if (currentError ||
1340
- get(formStateRef.current.errors, parentNodeName)) {
1341
- name = parentNodeName;
1342
- }
1343
- }
1344
- isValid = isEmptyObject(errors);
1345
- }
1346
- else {
1347
- error = (await validateField(field, get(getValues(), name), isValidateAllFieldCriteria, shouldUseNativeValidation))[name];
1348
- }
1349
- !isBlurEvent &&
1350
- subjectsRef.current.watch.next({
1351
- name,
1352
- type,
1353
- values: getValues(),
1354
- });
1355
- shouldRenderBaseOnError(false, name, error, inputState, isValid, isWatched);
1413
+ handleValidate(target, fieldState, isWatched, isBlurEvent);
1356
1414
  }
1357
1415
  }, []);
1358
1416
  const getValues = (fieldNames) => {
1359
- const values = Object.assign(Object.assign({}, defaultValuesRef.current), _formValues.current);
1417
+ const values = Object.assign(Object.assign({}, defaultValuesRef.current), getFieldsValues(fieldsRef));
1360
1418
  return isUndefined(fieldNames)
1361
1419
  ? values
1362
1420
  : isString(fieldNames)
@@ -1383,12 +1441,12 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1383
1441
  };
1384
1442
  const watchInternal = React.useCallback((fieldNames, defaultValue, isGlobal, formValues) => {
1385
1443
  const isArrayNames = Array.isArray(fieldNames);
1386
- const fieldValues = Object.assign({}, (formValues || isMountedRef.current
1387
- ? Object.assign(Object.assign({}, defaultValuesRef.current), (formValues || getValues())) : isUndefined(defaultValue)
1444
+ const fieldValues = formValues || isMountedRef.current
1445
+ ? Object.assign(Object.assign({}, defaultValuesRef.current), (formValues || getFieldsValues(fieldsRef))) : isUndefined(defaultValue)
1388
1446
  ? defaultValuesRef.current
1389
1447
  : isArrayNames
1390
1448
  ? defaultValue
1391
- : { [fieldNames]: defaultValue }));
1449
+ : { [fieldNames]: defaultValue };
1392
1450
  if (isUndefined(fieldNames)) {
1393
1451
  isGlobal && (namesRef.current.watchAll = true);
1394
1452
  return fieldValues;
@@ -1398,12 +1456,7 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1398
1456
  isGlobal && namesRef.current.watch.add(fieldName);
1399
1457
  result.push(get(fieldValues, fieldName));
1400
1458
  }
1401
- return isArrayNames
1402
- ? result
1403
- : isObject(result[0])
1404
- ? Object.assign({}, result[0]) : Array.isArray(result[0])
1405
- ? [...result[0]]
1406
- : result[0];
1459
+ return isArrayNames ? result : result[0];
1407
1460
  }, []);
1408
1461
  const watch = (fieldName, defaultValue) => isFunction(fieldName)
1409
1462
  ? subjectsRef.current.watch.subscribe({
@@ -1417,11 +1470,8 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1417
1470
  namesRef.current.mount.delete(inputName);
1418
1471
  namesRef.current.array.delete(inputName);
1419
1472
  if (get(fieldsRef.current, inputName)) {
1420
- if (!options.keepValue) {
1421
- unset(fieldsRef.current, inputName);
1422
- unset(_formValues.current, inputName);
1423
- }
1424
1473
  !options.keepError && unset(formStateRef.current.errors, inputName);
1474
+ !options.keepValue && unset(fieldsRef.current, inputName);
1425
1475
  !options.keepDirty &&
1426
1476
  unset(formStateRef.current.dirtyFields, inputName);
1427
1477
  !options.keepTouched &&
@@ -1461,22 +1511,15 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1461
1511
  set(fieldsRef.current, name, {
1462
1512
  _f: Object.assign(Object.assign(Object.assign({}, (field && field._f ? field._f : { ref: { name } })), { name, mount: true }), options),
1463
1513
  });
1464
- if (options.value) {
1465
- set(_formValues.current, name, options.value);
1466
- }
1467
- if (!isUndefined(options.disabled) &&
1468
- field &&
1469
- field._f &&
1470
- field._f.ref.disabled !== options.disabled) {
1471
- set(_formValues.current, name, options.disabled ? undefined : field._f.ref.value);
1472
- }
1473
1514
  namesRef.current.mount.add(name);
1474
- !field && updateIsValidAndInputValue(name);
1515
+ !field && updateIsValidAndInputValue(name, undefined, true);
1475
1516
  return isWindowUndefined
1476
1517
  ? { name: name }
1477
- : Object.assign(Object.assign({ name }, (isUndefined(options.disabled)
1478
- ? {}
1479
- : { disabled: options.disabled })), { onChange: handleChange, onBlur: handleChange, ref: (ref) => {
1518
+ : {
1519
+ name,
1520
+ onChange: handleChange,
1521
+ onBlur: handleChange,
1522
+ ref: (ref) => {
1480
1523
  if (ref) {
1481
1524
  registerFieldRef(name, ref, options);
1482
1525
  }
@@ -1485,13 +1528,20 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1485
1528
  const shouldUnmount = shouldUnregister || options.shouldUnregister;
1486
1529
  if (field._f) {
1487
1530
  field._f.mount = false;
1531
+ // If initial state of field element is disabled,
1532
+ // value is not set on first "register"
1533
+ // re-sync the value in when it switched to enabled
1534
+ if (isUndefined(field._f.value)) {
1535
+ field._f.value = field._f.ref.value;
1536
+ }
1488
1537
  }
1489
1538
  shouldUnmount &&
1490
1539
  !(isNameInFieldArray(namesRef.current.array, name) &&
1491
1540
  inFieldArrayActionRef.current) &&
1492
1541
  namesRef.current.unMount.add(name);
1493
1542
  }
1494
- } });
1543
+ },
1544
+ };
1495
1545
  }, []);
1496
1546
  const handleSubmit = React.useCallback((onValid, onInvalid) => async (e) => {
1497
1547
  if (e) {
@@ -1499,7 +1549,7 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1499
1549
  e.persist && e.persist();
1500
1550
  }
1501
1551
  let hasNoPromiseError = true;
1502
- let fieldValues = Object.assign({}, _formValues.current);
1552
+ let fieldValues = getFieldsValues(fieldsRef);
1503
1553
  subjectsRef.current.state.next({
1504
1554
  isSubmitting: true,
1505
1555
  });
@@ -1584,7 +1634,6 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1584
1634
  }
1585
1635
  if (!keepStateOptions.keepValues) {
1586
1636
  fieldsRef.current = {};
1587
- _formValues.current = {};
1588
1637
  subjectsRef.current.control.next({
1589
1638
  values: keepStateOptions.keepDefaultValues
1590
1639
  ? defaultValuesRef.current
@@ -1642,8 +1691,9 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1642
1691
  const useFieldArraySubscription = subjectsRef.current.array.subscribe({
1643
1692
  next(state) {
1644
1693
  if (state.values && state.name && readFormStateRef.current.isValid) {
1645
- set(_formValues.current, state.name, state.values);
1646
- updateIsValid();
1694
+ const values = getFieldsValues(fieldsRef);
1695
+ set(values, state.name, state.values);
1696
+ updateIsValid(values);
1647
1697
  }
1648
1698
  },
1649
1699
  });
@@ -1687,7 +1737,6 @@ function useForm({ mode = VALIDATION_MODE.onSubmit, reValidateMode = VALIDATION_
1687
1737
  defaultValuesRef,
1688
1738
  fieldArrayDefaultValuesRef,
1689
1739
  setValues,
1690
- _formValues,
1691
1740
  unregister,
1692
1741
  shouldUnmount: shouldUnregister,
1693
1742
  }), []),