react-hook-form 7.84.0 → 7.85.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/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.mjs +198 -91
- package/dist/index.esm.mjs.map +1 -1
- 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/unsetEmptyArray.d.ts +1 -1
- package/dist/logic/unsetEmptyArray.d.ts.map +1 -1
- package/dist/logic/validateField.d.ts.map +1 -1
- package/dist/react-server.esm.mjs +63 -15
- package/dist/react-server.esm.mjs.map +1 -1
- package/dist/types/errors.d.ts +6 -1
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/form.d.ts +3 -2
- package/dist/types/form.d.ts.map +1 -1
- package/dist/useFieldArray.d.ts.map +1 -1
- package/dist/useForm.d.ts.map +1 -1
- package/dist/useFormState.d.ts.map +1 -1
- package/dist/useResyncOnReconnect.d.ts +5 -0
- package/dist/useResyncOnReconnect.d.ts.map +1 -0
- package/dist/useWatch.d.ts.map +1 -1
- package/package.json +2 -6
- package/dist/logic/getNodeParentName.d.ts +0 -3
- package/dist/logic/getNodeParentName.d.ts.map +0 -1
- package/dist/utils/deepMerge.d.ts +0 -2
- package/dist/utils/deepMerge.d.ts.map +0 -1
package/dist/index.esm.mjs
CHANGED
|
@@ -170,6 +170,82 @@ const useIsomorphicLayoutEffect = isWeb
|
|
|
170
170
|
? React.useLayoutEffect
|
|
171
171
|
: React.useEffect;
|
|
172
172
|
|
|
173
|
+
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
174
|
+
|
|
175
|
+
const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
|
|
176
|
+
function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
177
|
+
if (object1 === object2) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
if (isPrimitive(object1) || isPrimitive(object2)) {
|
|
181
|
+
return Object.is(object1, object2);
|
|
182
|
+
}
|
|
183
|
+
if (isDateObject(object1) && isDateObject(object2)) {
|
|
184
|
+
return Object.is(object1.getTime(), object2.getTime());
|
|
185
|
+
}
|
|
186
|
+
const keys1 = Object.keys(object1);
|
|
187
|
+
const keys2 = Object.keys(object2);
|
|
188
|
+
if (keys1.length !== keys2.length) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
|
|
192
|
+
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
193
|
+
return Object.is(object1, object2);
|
|
194
|
+
}
|
|
195
|
+
if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
const visitedPairs = visited.get(object1);
|
|
199
|
+
if (visitedPairs && visitedPairs.has(object2)) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
if (visitedPairs) {
|
|
203
|
+
visitedPairs.add(object2);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
const ws = new WeakSet();
|
|
207
|
+
ws.add(object2);
|
|
208
|
+
visited.set(object1, ws);
|
|
209
|
+
}
|
|
210
|
+
for (const key of keys1) {
|
|
211
|
+
const val1 = object1[key];
|
|
212
|
+
if (!(key in object2)) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
if (key !== 'ref') {
|
|
216
|
+
const val2 = object2[key];
|
|
217
|
+
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
218
|
+
((isObject(val1) || Array.isArray(val1)) &&
|
|
219
|
+
(isObject(val2) || Array.isArray(val2)))
|
|
220
|
+
? !deepEqual(val1, val2, visited)
|
|
221
|
+
: !Object.is(val1, val2)) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function useResyncOnReconnect() {
|
|
230
|
+
const _connected = React.useRef(false);
|
|
231
|
+
const _prevValue = React.useRef(undefined);
|
|
232
|
+
const resyncIfNeeded = React.useCallback((enabled, getCurrentValue, setValue) => {
|
|
233
|
+
if (enabled && _connected.current) {
|
|
234
|
+
const currentValue = getCurrentValue();
|
|
235
|
+
if (!deepEqual(_prevValue.current, currentValue)) {
|
|
236
|
+
setValue(currentValue);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
_connected.current = true;
|
|
240
|
+
}, []);
|
|
241
|
+
const snapshot = React.useCallback((enabled, getCurrentValue) => {
|
|
242
|
+
if (enabled) {
|
|
243
|
+
_prevValue.current = cloneObject(getCurrentValue());
|
|
244
|
+
}
|
|
245
|
+
}, []);
|
|
246
|
+
return { resyncIfNeeded, snapshot };
|
|
247
|
+
}
|
|
248
|
+
|
|
173
249
|
/**
|
|
174
250
|
* Subscribes to each form state and isolates re-renders at the custom hook level. It has its own scope for form state subscriptions, so it will not affect other useFormState or useForm instances. Using this hook can reduce the re-render impact on large and complex form applications.
|
|
175
251
|
*
|
|
@@ -217,19 +293,31 @@ function useFormState(props) {
|
|
|
217
293
|
isValid: false,
|
|
218
294
|
errors: false,
|
|
219
295
|
});
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
296
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
297
|
+
useIsomorphicLayoutEffect(() => {
|
|
298
|
+
const getCurrentFormState = () => ({
|
|
299
|
+
...control._formState,
|
|
300
|
+
defaultValues: control._defaultValues,
|
|
301
|
+
});
|
|
302
|
+
resyncIfNeeded(!disabled, getCurrentFormState, updateFormState);
|
|
303
|
+
const unsubscribe = control._subscribe({
|
|
304
|
+
name,
|
|
305
|
+
formState: _localProxyFormState.current,
|
|
306
|
+
exact,
|
|
307
|
+
callback: (formState) => {
|
|
308
|
+
!disabled &&
|
|
309
|
+
updateFormState({
|
|
310
|
+
...control._formState,
|
|
311
|
+
...formState,
|
|
312
|
+
defaultValues: control._defaultValues,
|
|
313
|
+
});
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
return () => {
|
|
317
|
+
unsubscribe();
|
|
318
|
+
snapshot(!disabled, getCurrentFormState);
|
|
319
|
+
};
|
|
320
|
+
}, [name, disabled, exact, resyncIfNeeded, snapshot]);
|
|
233
321
|
React.useEffect(() => {
|
|
234
322
|
_localProxyFormState.current.isValid && control._setValid(true);
|
|
235
323
|
}, [control]);
|
|
@@ -251,62 +339,6 @@ var generateWatchOutput = (names, _names, formValues, isGlobal, defaultValue) =>
|
|
|
251
339
|
return formValues;
|
|
252
340
|
};
|
|
253
341
|
|
|
254
|
-
var isPrimitive = (value) => isNullOrUndefined(value) || !isObjectType(value);
|
|
255
|
-
|
|
256
|
-
const isEmptyObjectWithCustomPrototype = (object, keys) => keys.length === 0 && !Array.isArray(object) && !isPlainObject(object);
|
|
257
|
-
function deepEqual(object1, object2, visited = new WeakMap()) {
|
|
258
|
-
if (object1 === object2) {
|
|
259
|
-
return true;
|
|
260
|
-
}
|
|
261
|
-
if (isPrimitive(object1) || isPrimitive(object2)) {
|
|
262
|
-
return Object.is(object1, object2);
|
|
263
|
-
}
|
|
264
|
-
if (isDateObject(object1) && isDateObject(object2)) {
|
|
265
|
-
return Object.is(object1.getTime(), object2.getTime());
|
|
266
|
-
}
|
|
267
|
-
const keys1 = Object.keys(object1);
|
|
268
|
-
const keys2 = Object.keys(object2);
|
|
269
|
-
if (keys1.length !== keys2.length) {
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
272
|
-
if (isEmptyObjectWithCustomPrototype(object1, keys1) ||
|
|
273
|
-
isEmptyObjectWithCustomPrototype(object2, keys2)) {
|
|
274
|
-
return Object.is(object1, object2);
|
|
275
|
-
}
|
|
276
|
-
if (!keys1.length && Array.isArray(object1) !== Array.isArray(object2)) {
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
const visitedPairs = visited.get(object1);
|
|
280
|
-
if (visitedPairs && visitedPairs.has(object2)) {
|
|
281
|
-
return true;
|
|
282
|
-
}
|
|
283
|
-
if (visitedPairs) {
|
|
284
|
-
visitedPairs.add(object2);
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
const ws = new WeakSet();
|
|
288
|
-
ws.add(object2);
|
|
289
|
-
visited.set(object1, ws);
|
|
290
|
-
}
|
|
291
|
-
for (const key of keys1) {
|
|
292
|
-
const val1 = object1[key];
|
|
293
|
-
if (!(key in object2)) {
|
|
294
|
-
return false;
|
|
295
|
-
}
|
|
296
|
-
if (key !== 'ref') {
|
|
297
|
-
const val2 = object2[key];
|
|
298
|
-
if ((isDateObject(val1) && isDateObject(val2)) ||
|
|
299
|
-
((isObject(val1) || Array.isArray(val1)) &&
|
|
300
|
-
(isObject(val2) || Array.isArray(val2)))
|
|
301
|
-
? !deepEqual(val1, val2, visited)
|
|
302
|
-
: !Object.is(val1, val2)) {
|
|
303
|
-
return false;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
342
|
/**
|
|
311
343
|
* Custom hook to subscribe to field changes and isolate re-rendering at the component level.
|
|
312
344
|
*
|
|
@@ -355,24 +387,39 @@ function useWatch(props) {
|
|
|
355
387
|
}
|
|
356
388
|
}
|
|
357
389
|
}, [control._formValues, control._names, disabled, name]);
|
|
390
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
391
|
+
const _refreshValue = React.useRef(refreshValue);
|
|
392
|
+
_refreshValue.current = refreshValue;
|
|
393
|
+
const _getCurrentOutput = React.useRef(getCurrentOutput);
|
|
394
|
+
_getCurrentOutput.current = getCurrentOutput;
|
|
358
395
|
useIsomorphicLayoutEffect(() => {
|
|
359
396
|
if (_prevControl.current !== control ||
|
|
360
397
|
!deepEqual(_prevName.current, name)) {
|
|
361
398
|
_prevControl.current = control;
|
|
362
399
|
_prevName.current = name;
|
|
363
|
-
|
|
400
|
+
_refreshValue.current();
|
|
364
401
|
}
|
|
365
|
-
|
|
402
|
+
else {
|
|
403
|
+
resyncIfNeeded(!disabled, () => _getCurrentOutput.current(), (currentValue) => {
|
|
404
|
+
updateValue(currentValue);
|
|
405
|
+
_computeFormValues.current = currentValue;
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
const unsubscribe = control._subscribe({
|
|
366
409
|
name,
|
|
367
410
|
formState: {
|
|
368
411
|
values: true,
|
|
369
412
|
},
|
|
370
413
|
exact,
|
|
371
414
|
callback: (formState) => {
|
|
372
|
-
|
|
415
|
+
_refreshValue.current(formState.values);
|
|
373
416
|
},
|
|
374
417
|
});
|
|
375
|
-
|
|
418
|
+
return () => {
|
|
419
|
+
unsubscribe();
|
|
420
|
+
snapshot(!disabled, () => _getCurrentOutput.current());
|
|
421
|
+
};
|
|
422
|
+
}, [control, exact, name, disabled, resyncIfNeeded, snapshot]);
|
|
376
423
|
React.useEffect(() => control._removeUnmounted());
|
|
377
424
|
// If name or control changed for this render, synchronously reflect the
|
|
378
425
|
// latest value so callers (like useController) see the correct value
|
|
@@ -830,7 +877,9 @@ var validateField = async (field, disabledFieldNames, formValues, validateAllFie
|
|
|
830
877
|
let exceedMin;
|
|
831
878
|
const maxOutput = getValueAndMessage(max);
|
|
832
879
|
const minOutput = getValueAndMessage(min);
|
|
833
|
-
if (!isNullOrUndefined(inputValue) &&
|
|
880
|
+
if (!isNullOrUndefined(inputValue) &&
|
|
881
|
+
!isDateObject(inputValue) &&
|
|
882
|
+
!isNaN(inputValue)) {
|
|
834
883
|
const valueNumber = ref.valueAsNumber ||
|
|
835
884
|
(inputValue ? +inputValue : inputValue);
|
|
836
885
|
if (!isNullOrUndefined(maxOutput.value)) {
|
|
@@ -1238,9 +1287,11 @@ function useFieldArray(props) {
|
|
|
1238
1287
|
};
|
|
1239
1288
|
React.useEffect(() => {
|
|
1240
1289
|
if (disabled) {
|
|
1290
|
+
control._state.actionArrayLengths.delete(name);
|
|
1241
1291
|
return;
|
|
1242
1292
|
}
|
|
1243
1293
|
control._state.action = false;
|
|
1294
|
+
control._state.actionArrayLengths.delete(name);
|
|
1244
1295
|
isWatched(name, control._names) &&
|
|
1245
1296
|
control._subjects.state.next({
|
|
1246
1297
|
...control._formState,
|
|
@@ -1320,6 +1371,7 @@ function useFieldArray(props) {
|
|
|
1320
1371
|
!get(control._formValues, name) && control._setFieldArray(name);
|
|
1321
1372
|
}
|
|
1322
1373
|
return () => {
|
|
1374
|
+
control._state.actionArrayLengths.delete(name);
|
|
1323
1375
|
if (disabled) {
|
|
1324
1376
|
return;
|
|
1325
1377
|
}
|
|
@@ -1964,7 +2016,12 @@ var skipValidation = (isBlurEvent, isTouched, isSubmitted, reValidateMode, mode)
|
|
|
1964
2016
|
return true;
|
|
1965
2017
|
};
|
|
1966
2018
|
|
|
1967
|
-
var unsetEmptyArray = (ref, name) =>
|
|
2019
|
+
var unsetEmptyArray = (ref, name) => {
|
|
2020
|
+
const array = get(ref, name);
|
|
2021
|
+
!compact(array).length &&
|
|
2022
|
+
!(array === null || array === void 0 ? void 0 : array.root) &&
|
|
2023
|
+
unset(ref, name);
|
|
2024
|
+
};
|
|
1968
2025
|
|
|
1969
2026
|
const defaultOptions = {
|
|
1970
2027
|
mode: VALIDATION_MODE.onSubmit,
|
|
@@ -2013,6 +2070,7 @@ function createFormControl(props = {}) {
|
|
|
2013
2070
|
: cloneObject(_defaultValues);
|
|
2014
2071
|
let _state = {
|
|
2015
2072
|
action: false,
|
|
2073
|
+
actionArrayLengths: new Map(),
|
|
2016
2074
|
mount: false,
|
|
2017
2075
|
watch: false,
|
|
2018
2076
|
keepIsValid: false,
|
|
@@ -2108,13 +2166,22 @@ function createFormControl(props = {}) {
|
|
|
2108
2166
|
const _setFieldArray = (name, values = [], method, args, shouldSetValues = true, shouldUpdateFieldsAndState = true) => {
|
|
2109
2167
|
if (args && method && !_options.disabled) {
|
|
2110
2168
|
_state.action = true;
|
|
2169
|
+
if (!_state.actionArrayLengths.has(name)) {
|
|
2170
|
+
const preActionFields = get(_fields, name);
|
|
2171
|
+
_state.actionArrayLengths.set(name, Array.isArray(preActionFields) ? preActionFields.length : 0);
|
|
2172
|
+
}
|
|
2111
2173
|
if (shouldUpdateFieldsAndState && Array.isArray(get(_fields, name))) {
|
|
2112
2174
|
const fieldValues = method(get(_fields, name), args.argA, args.argB);
|
|
2113
2175
|
shouldSetValues && set(_fields, name, fieldValues);
|
|
2114
2176
|
}
|
|
2115
2177
|
if (shouldUpdateFieldsAndState &&
|
|
2116
2178
|
Array.isArray(get(_formState.errors, name))) {
|
|
2117
|
-
const
|
|
2179
|
+
const fieldArrayErrors = get(_formState.errors, name);
|
|
2180
|
+
const rootError = fieldArrayErrors.root;
|
|
2181
|
+
const errors = method(fieldArrayErrors, args.argA, args.argB) || fieldArrayErrors;
|
|
2182
|
+
if (rootError) {
|
|
2183
|
+
errors.root = rootError;
|
|
2184
|
+
}
|
|
2118
2185
|
shouldSetValues && set(_formState.errors, name, errors);
|
|
2119
2186
|
unsetEmptyArray(_formState.errors, name);
|
|
2120
2187
|
}
|
|
@@ -2170,10 +2237,40 @@ function createFormControl(props = {}) {
|
|
|
2170
2237
|
}
|
|
2171
2238
|
return false;
|
|
2172
2239
|
};
|
|
2240
|
+
const isStaleArrayIndex = (name) => {
|
|
2241
|
+
if (!_state.actionArrayLengths.size) {
|
|
2242
|
+
return false;
|
|
2243
|
+
}
|
|
2244
|
+
const segments = isKey(name) ? [name] : stringToPath(name);
|
|
2245
|
+
let node = _formValues;
|
|
2246
|
+
let path = '';
|
|
2247
|
+
let ownerDepth = -1;
|
|
2248
|
+
let ownerPreActionLength = 0;
|
|
2249
|
+
for (let i = 0; i < segments.length; i++) {
|
|
2250
|
+
if (isNullOrUndefined(node)) {
|
|
2251
|
+
return false;
|
|
2252
|
+
}
|
|
2253
|
+
const key = segments[i];
|
|
2254
|
+
path = path ? `${path}.${key}` : key;
|
|
2255
|
+
if (Array.isArray(node) && +key >= node.length) {
|
|
2256
|
+
return ownerDepth === -1
|
|
2257
|
+
? false
|
|
2258
|
+
: i === ownerDepth
|
|
2259
|
+
? +key < ownerPreActionLength
|
|
2260
|
+
: true;
|
|
2261
|
+
}
|
|
2262
|
+
if (_state.actionArrayLengths.has(path)) {
|
|
2263
|
+
ownerDepth = i + 1;
|
|
2264
|
+
ownerPreActionLength = _state.actionArrayLengths.get(path);
|
|
2265
|
+
}
|
|
2266
|
+
node = node[key];
|
|
2267
|
+
}
|
|
2268
|
+
return false;
|
|
2269
|
+
};
|
|
2173
2270
|
const updateValidAndValue = (name, shouldSkipSetValueAs, value, ref) => {
|
|
2174
2271
|
const field = get(_fields, name);
|
|
2175
2272
|
if (field) {
|
|
2176
|
-
if (hasExplicitNullIntermediate(name)) {
|
|
2273
|
+
if (hasExplicitNullIntermediate(name) || isStaleArrayIndex(name)) {
|
|
2177
2274
|
return;
|
|
2178
2275
|
}
|
|
2179
2276
|
const wasUnsetInFormValues = isUndefined(get(_formValues, name));
|
|
@@ -2421,14 +2518,12 @@ function createFormControl(props = {}) {
|
|
|
2421
2518
|
const _getWatch = (names, defaultValue, isGlobal) => generateWatchOutput(names, _names, {
|
|
2422
2519
|
...(_state.mount
|
|
2423
2520
|
? _formValues
|
|
2424
|
-
: isUndefined(defaultValue)
|
|
2521
|
+
: isUndefined(defaultValue) || isString(names)
|
|
2425
2522
|
? _defaultValues
|
|
2426
|
-
:
|
|
2427
|
-
? { [names]: defaultValue }
|
|
2428
|
-
: defaultValue),
|
|
2523
|
+
: defaultValue),
|
|
2429
2524
|
}, isGlobal, defaultValue);
|
|
2430
2525
|
const _getFieldArray = (name) => compact(get(_state.mount ? _formValues : _defaultValues, name, _options.shouldUnregister ? get(_defaultValues, name, []) : []));
|
|
2431
|
-
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false) => {
|
|
2526
|
+
const setFieldValue = (name, value, options = {}, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
2432
2527
|
const field = get(_fields, name);
|
|
2433
2528
|
let fieldValue = value;
|
|
2434
2529
|
if (field) {
|
|
@@ -2466,7 +2561,7 @@ function createFormControl(props = {}) {
|
|
|
2466
2561
|
}
|
|
2467
2562
|
else {
|
|
2468
2563
|
fieldReference.ref.value = fieldValue;
|
|
2469
|
-
if (!fieldReference.ref.type && !skipRender) {
|
|
2564
|
+
if (!fieldReference.ref.type && !skipRender && !skipValueRender) {
|
|
2470
2565
|
_subjects.state.next({
|
|
2471
2566
|
name,
|
|
2472
2567
|
values: skipClone ? _formValues : cloneObject(_formValues),
|
|
@@ -2482,7 +2577,7 @@ function createFormControl(props = {}) {
|
|
|
2482
2577
|
delayError: options.delayError,
|
|
2483
2578
|
});
|
|
2484
2579
|
};
|
|
2485
|
-
const setFieldValues = (name, value, options, skipClone = false, skipRender = false) => {
|
|
2580
|
+
const setFieldValues = (name, value, options, skipClone = false, skipRender = false, skipValueRender = false) => {
|
|
2486
2581
|
if (_names.array.has(name)) {
|
|
2487
2582
|
_subjects.array.next({
|
|
2488
2583
|
name,
|
|
@@ -2500,8 +2595,8 @@ function createFormControl(props = {}) {
|
|
|
2500
2595
|
isObject(fieldValue) ||
|
|
2501
2596
|
(field && !field._f)) &&
|
|
2502
2597
|
!isDateObject(fieldValue)
|
|
2503
|
-
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender)
|
|
2504
|
-
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender);
|
|
2598
|
+
? setFieldValues(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender)
|
|
2599
|
+
: setFieldValue(fieldName, fieldValue, options, skipClone, skipRender, skipValueRender);
|
|
2505
2600
|
}
|
|
2506
2601
|
};
|
|
2507
2602
|
const _setValue = (name, value, options, skipClone, skipStateEmit = false) => {
|
|
@@ -2536,11 +2631,12 @@ function createFormControl(props = {}) {
|
|
|
2536
2631
|
else {
|
|
2537
2632
|
const isEmpty = (Array.isArray(cloneValue) && !cloneValue.length) ||
|
|
2538
2633
|
isEmptyObject(cloneValue);
|
|
2634
|
+
const skipValueRender = !isValueUnchanged && !skipStateEmit;
|
|
2539
2635
|
if (!field || field._f || isNullOrUndefined(cloneValue) || isEmpty) {
|
|
2540
|
-
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit);
|
|
2636
|
+
setFieldValue(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
2541
2637
|
}
|
|
2542
2638
|
else {
|
|
2543
|
-
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit);
|
|
2639
|
+
setFieldValues(name, cloneValue, options, skipClone, skipStateEmit, skipValueRender);
|
|
2544
2640
|
}
|
|
2545
2641
|
}
|
|
2546
2642
|
if (!isValueUnchanged && !skipStateEmit) {
|
|
@@ -3202,6 +3298,7 @@ function createFormControl(props = {}) {
|
|
|
3202
3298
|
_state.watch = !!_options.shouldUnregister;
|
|
3203
3299
|
_state.keepIsValid = !!keepStateOptions.keepIsValid;
|
|
3204
3300
|
_state.action = false;
|
|
3301
|
+
_state.actionArrayLengths.clear();
|
|
3205
3302
|
if (!keepStateOptions.keepErrors) {
|
|
3206
3303
|
_formState.errors = {};
|
|
3207
3304
|
}
|
|
@@ -3274,6 +3371,7 @@ function createFormControl(props = {}) {
|
|
|
3274
3371
|
...formState,
|
|
3275
3372
|
};
|
|
3276
3373
|
};
|
|
3374
|
+
_subjects.state.subscribe({ next: _setFormState });
|
|
3277
3375
|
const _resetDefaultValues = () => isFunction(_options.defaultValues) &&
|
|
3278
3376
|
_options.defaultValues().then((values) => {
|
|
3279
3377
|
reset(values, _options.resetOptions);
|
|
@@ -3443,8 +3541,14 @@ function useForm(props = {}) {
|
|
|
3443
3541
|
}
|
|
3444
3542
|
const control = _formControl.current.control;
|
|
3445
3543
|
control._options = props;
|
|
3544
|
+
const { resyncIfNeeded, snapshot } = useResyncOnReconnect();
|
|
3446
3545
|
useIsomorphicLayoutEffect(() => {
|
|
3447
|
-
const
|
|
3546
|
+
const getCurrentFormState = () => ({
|
|
3547
|
+
...control._formState,
|
|
3548
|
+
defaultValues: control._defaultValues,
|
|
3549
|
+
});
|
|
3550
|
+
resyncIfNeeded(true, getCurrentFormState, updateFormState);
|
|
3551
|
+
const unsubscribe = control._subscribe({
|
|
3448
3552
|
formState: control._proxyFormState,
|
|
3449
3553
|
callback: () => updateFormState({
|
|
3450
3554
|
...control._formState,
|
|
@@ -3457,8 +3561,11 @@ function useForm(props = {}) {
|
|
|
3457
3561
|
isReady: true,
|
|
3458
3562
|
}));
|
|
3459
3563
|
control._formState.isReady = true;
|
|
3460
|
-
return
|
|
3461
|
-
|
|
3564
|
+
return () => {
|
|
3565
|
+
unsubscribe();
|
|
3566
|
+
snapshot(true, getCurrentFormState);
|
|
3567
|
+
};
|
|
3568
|
+
}, [control, resyncIfNeeded, snapshot]);
|
|
3462
3569
|
React.useEffect(() => control._disableForm(props.disabled), [control, props.disabled]);
|
|
3463
3570
|
React.useEffect(() => {
|
|
3464
3571
|
if (props.mode) {
|