Skip to content

Commit 08d610f

Browse files
fix: meta should not regenerate every render (#1114)
* fix: meta should not regenerate every render * ci: apply automated fixes and generate docs * chore: tests now pass * ci: apply automated fixes and generate docs * chore: add test to validate patch * chore: fix linter --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent b60264c commit 08d610f

File tree

3 files changed

+97
-23
lines changed

3 files changed

+97
-23
lines changed

docs/reference/classes/formapi.md

+21-21
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ Defined in: [packages/form-core/src/FormApi.ts:377](https://github.com/TanStack/
119119
deleteField<TField>(field): void
120120
```
121121
122-
Defined in: [packages/form-core/src/FormApi.ts:1182](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1182)
122+
Defined in: [packages/form-core/src/FormApi.ts:1194](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1194)
123123
124124
#### Type Parameters
125125
@@ -143,7 +143,7 @@ Defined in: [packages/form-core/src/FormApi.ts:1182](https://github.com/TanStack
143143
getFieldInfo<TField>(field): FieldInfo<TFormData, TFormValidator>
144144
```
145145
146-
Defined in: [packages/form-core/src/FormApi.ts:1091](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1091)
146+
Defined in: [packages/form-core/src/FormApi.ts:1103](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1103)
147147
148148
Gets the field info of the specified field.
149149
@@ -169,7 +169,7 @@ Gets the field info of the specified field.
169169
getFieldMeta<TField>(field): undefined | FieldMeta
170170
```
171171
172-
Defined in: [packages/form-core/src/FormApi.ts:1082](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1082)
172+
Defined in: [packages/form-core/src/FormApi.ts:1094](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1094)
173173
174174
Gets the metadata of the specified field.
175175
@@ -195,7 +195,7 @@ Gets the metadata of the specified field.
195195
getFieldValue<TField>(field): DeepValue<TFormData, TField, IsNullable<TFormData>>
196196
```
197197
198-
Defined in: [packages/form-core/src/FormApi.ts:1075](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1075)
198+
Defined in: [packages/form-core/src/FormApi.ts:1087](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1087)
199199
200200
Gets the value of the specified field.
201201
@@ -221,7 +221,7 @@ Gets the value of the specified field.
221221
handleSubmit(): Promise<void>
222222
```
223223
224-
Defined in: [packages/form-core/src/FormApi.ts:1016](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1016)
224+
Defined in: [packages/form-core/src/FormApi.ts:1028](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1028)
225225
226226
Handles the form submission, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks.
227227
@@ -241,7 +241,7 @@ insertFieldValue<TField>(
241241
opts?): Promise<void>
242242
```
243243
244-
Defined in: [packages/form-core/src/FormApi.ts:1214](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1214)
244+
Defined in: [packages/form-core/src/FormApi.ts:1226](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1226)
245245
246246
Inserts a value into an array field at the specified index, shifting the subsequent values to the right.
247247
@@ -279,7 +279,7 @@ Inserts a value into an array field at the specified index, shifting the subsequ
279279
mount(): () => void
280280
```
281281
282-
Defined in: [packages/form-core/src/FormApi.ts:595](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L595)
282+
Defined in: [packages/form-core/src/FormApi.ts:607](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L607)
283283
284284
#### Returns
285285
@@ -301,7 +301,7 @@ moveFieldValues<TField>(
301301
opts?): void
302302
```
303303
304-
Defined in: [packages/form-core/src/FormApi.ts:1332](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1332)
304+
Defined in: [packages/form-core/src/FormApi.ts:1344](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1344)
305305
306306
Moves the value at the first specified index to the second specified index within an array field.
307307
@@ -342,7 +342,7 @@ pushFieldValue<TField>(
342342
opts?): void
343343
```
344344
345-
Defined in: [packages/form-core/src/FormApi.ts:1196](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1196)
345+
Defined in: [packages/form-core/src/FormApi.ts:1208](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1208)
346346
347347
Pushes a value into an array field.
348348
@@ -379,7 +379,7 @@ removeFieldValue<TField>(
379379
opts?): Promise<void>
380380
```
381381
382-
Defined in: [packages/form-core/src/FormApi.ts:1267](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1267)
382+
Defined in: [packages/form-core/src/FormApi.ts:1279](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1279)
383383
384384
Removes a value from an array field at the specified index.
385385
@@ -417,7 +417,7 @@ replaceFieldValue<TField>(
417417
opts?): Promise<void>
418418
```
419419
420-
Defined in: [packages/form-core/src/FormApi.ts:1241](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1241)
420+
Defined in: [packages/form-core/src/FormApi.ts:1253](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1253)
421421
422422
Replaces a value into an array field at the specified index.
423423
@@ -455,7 +455,7 @@ Replaces a value into an array field at the specified index.
455455
reset(values?, opts?): void
456456
```
457457
458-
Defined in: [packages/form-core/src/FormApi.ts:656](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L656)
458+
Defined in: [packages/form-core/src/FormApi.ts:668](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L668)
459459
460460
Resets the form state to the default values.
461461
If values are provided, the form will be reset to those values instead and the default values will be updated.
@@ -488,7 +488,7 @@ Optional options to control the reset behavior.
488488
resetFieldMeta<TField>(fieldMeta): Record<TField, FieldMeta>
489489
```
490490
491-
Defined in: [packages/form-core/src/FormApi.ts:1128](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1128)
491+
Defined in: [packages/form-core/src/FormApi.ts:1140](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1140)
492492
493493
#### Type Parameters
494494
@@ -512,7 +512,7 @@ Defined in: [packages/form-core/src/FormApi.ts:1128](https://github.com/TanStack
512512
setErrorMap(errorMap): void
513513
```
514514
515-
Defined in: [packages/form-core/src/FormApi.ts:1356](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1356)
515+
Defined in: [packages/form-core/src/FormApi.ts:1368](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1368)
516516
517517
Updates the form's errorMap
518518
@@ -534,7 +534,7 @@ Updates the form's errorMap
534534
setFieldMeta<TField>(field, updater): void
535535
```
536536
537-
Defined in: [packages/form-core/src/FormApi.ts:1110](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1110)
537+
Defined in: [packages/form-core/src/FormApi.ts:1122](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1122)
538538
539539
Updates the metadata of the specified field.
540540
@@ -567,7 +567,7 @@ setFieldValue<TField>(
567567
opts?): void
568568
```
569569
570-
Defined in: [packages/form-core/src/FormApi.ts:1152](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1152)
570+
Defined in: [packages/form-core/src/FormApi.ts:1164](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1164)
571571
572572
Sets the value of the specified field and optionally updates the touched state.
573573
@@ -605,7 +605,7 @@ swapFieldValues<TField>(
605605
opts?): void
606606
```
607607
608-
Defined in: [packages/form-core/src/FormApi.ts:1306](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1306)
608+
Defined in: [packages/form-core/src/FormApi.ts:1318](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1318)
609609
610610
Swaps the values at the specified indices within an array field.
611611
@@ -643,7 +643,7 @@ Swaps the values at the specified indices within an array field.
643643
update(options?): void
644644
```
645645
646-
Defined in: [packages/form-core/src/FormApi.ts:612](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L612)
646+
Defined in: [packages/form-core/src/FormApi.ts:624](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L624)
647647
648648
Updates the form options and form state.
649649
@@ -665,7 +665,7 @@ Updates the form options and form state.
665665
validateAllFields(cause): Promise<ValidationError[]>
666666
```
667667
668-
Defined in: [packages/form-core/src/FormApi.ts:682](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L682)
668+
Defined in: [packages/form-core/src/FormApi.ts:694](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L694)
669669
670670
Validates form and all fields in using the correct handlers for a given validation cause.
671671
@@ -690,7 +690,7 @@ validateArrayFieldsStartingFrom<TField>(
690690
cause): Promise<ValidationError[]>
691691
```
692692
693-
Defined in: [packages/form-core/src/FormApi.ts:710](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L710)
693+
Defined in: [packages/form-core/src/FormApi.ts:722](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L722)
694694
695695
Validates the children of a specified array in the form starting from a given index until the end using the correct handlers for a given validation type.
696696
@@ -726,7 +726,7 @@ validateField<TField>(field, cause):
726726
| Promise<ValidationError[]>
727727
```
728728
729-
Defined in: [packages/form-core/src/FormApi.ts:749](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L749)
729+
Defined in: [packages/form-core/src/FormApi.ts:761](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L761)
730730
731731
Validates a specified field in the form using the correct handlers for a given validation type.
732732

packages/form-core/src/FormApi.ts

+14-2
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,10 @@ export class FormApi<
416416
fieldName as never
417417
] as FieldMetaBase | undefined
418418

419-
let fieldErrors =
420-
prevVal?.[fieldName as never as keyof typeof prevVal]?.errors
419+
const prevFieldInfo =
420+
prevVal?.[fieldName as never as keyof typeof prevVal]
421+
422+
let fieldErrors = prevFieldInfo?.errors
421423
if (!prevBaseVal || currBaseVal.errorMap !== prevBaseVal.errorMap) {
422424
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
423425
fieldErrors = Object.values(currBaseVal.errorMap ?? {}).filter(
@@ -428,6 +430,16 @@ export class FormApi<
428430
// As a primitive, we don't need to aggressively persist the same referencial value for performance reasons
429431
const isFieldPristine = !currBaseVal.isDirty
430432

433+
if (
434+
prevFieldInfo &&
435+
prevFieldInfo.isPristine === isFieldPristine &&
436+
prevFieldInfo.errors === fieldErrors &&
437+
currBaseVal === prevBaseVal
438+
) {
439+
fieldMeta[fieldName] = prevFieldInfo
440+
continue
441+
}
442+
431443
fieldMeta[fieldName] = {
432444
...currBaseVal,
433445
errors: fieldErrors,

packages/react-form/tests/useField.test.tsx

+62
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable react-compiler/react-compiler */
12
import { describe, expect, it, vi } from 'vitest'
23
import { render, waitFor } from '@testing-library/react'
34
import { userEvent } from '@testing-library/user-event'
@@ -1068,4 +1069,65 @@ describe('useField', () => {
10681069
await user.click(getByText('Add person'))
10691070
expect(getByText(`["Test"]`)).toBeInTheDocument()
10701071
})
1072+
1073+
it('should not rerender unrelated fields', async () => {
1074+
const renderCount = {
1075+
field1: 0,
1076+
field2: 0,
1077+
}
1078+
1079+
function Comp() {
1080+
const form = useForm({
1081+
defaultValues: {
1082+
field1: '',
1083+
field2: '',
1084+
},
1085+
})
1086+
1087+
return (
1088+
<>
1089+
<form.Field name="field1">
1090+
{(field) => {
1091+
renderCount.field1++
1092+
return (
1093+
<input
1094+
data-testid="field1"
1095+
value={field.state.value}
1096+
onChange={(e) => field.handleChange(e.target.value)}
1097+
/>
1098+
)
1099+
}}
1100+
</form.Field>
1101+
<form.Field name="field2">
1102+
{(field) => {
1103+
renderCount.field2++
1104+
return (
1105+
<input
1106+
data-testid="field2"
1107+
value={field.state.value}
1108+
onChange={(e) => field.handleChange(e.target.value)}
1109+
/>
1110+
)
1111+
}}
1112+
</form.Field>
1113+
</>
1114+
)
1115+
}
1116+
1117+
const { getByTestId } = render(
1118+
<StrictMode>
1119+
<Comp />
1120+
</StrictMode>,
1121+
)
1122+
1123+
const field1InitialRender = renderCount.field1
1124+
const field2InitialRender = renderCount.field2
1125+
1126+
await user.type(getByTestId('field1'), 'test')
1127+
1128+
// field1 should have rerendered
1129+
expect(renderCount.field1).toBeGreaterThan(field1InitialRender)
1130+
// field2 should not have rerendered
1131+
expect(renderCount.field2).toBe(field2InitialRender)
1132+
})
10711133
})

0 commit comments

Comments
 (0)