Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: meta should not regenerate every render #1114

Merged
merged 7 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 21 additions & 21 deletions docs/reference/classes/formapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Defined in: [packages/form-core/src/FormApi.ts:377](https://github.com/TanStack/
deleteField<TField>(field): void
```

Defined in: [packages/form-core/src/FormApi.ts:1182](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1182)
Defined in: [packages/form-core/src/FormApi.ts:1194](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1194)

#### Type Parameters

Expand All @@ -143,7 +143,7 @@ Defined in: [packages/form-core/src/FormApi.ts:1182](https://github.com/TanStack
getFieldInfo<TField>(field): FieldInfo<TFormData, TFormValidator>
```

Defined in: [packages/form-core/src/FormApi.ts:1091](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1091)
Defined in: [packages/form-core/src/FormApi.ts:1103](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1103)

Gets the field info of the specified field.

Expand All @@ -169,7 +169,7 @@ Gets the field info of the specified field.
getFieldMeta<TField>(field): undefined | FieldMeta
```

Defined in: [packages/form-core/src/FormApi.ts:1082](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1082)
Defined in: [packages/form-core/src/FormApi.ts:1094](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1094)

Gets the metadata of the specified field.

Expand All @@ -195,7 +195,7 @@ Gets the metadata of the specified field.
getFieldValue<TField>(field): DeepValue<TFormData, TField, IsNullable<TFormData>>
```

Defined in: [packages/form-core/src/FormApi.ts:1075](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1075)
Defined in: [packages/form-core/src/FormApi.ts:1087](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1087)

Gets the value of the specified field.

Expand All @@ -221,7 +221,7 @@ Gets the value of the specified field.
handleSubmit(): Promise<void>
```

Defined in: [packages/form-core/src/FormApi.ts:1016](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1016)
Defined in: [packages/form-core/src/FormApi.ts:1028](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1028)

Handles the form submission, performs validation, and calls the appropriate onSubmit or onInvalidSubmit callbacks.

Expand All @@ -241,7 +241,7 @@ insertFieldValue<TField>(
opts?): Promise<void>
```

Defined in: [packages/form-core/src/FormApi.ts:1214](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1214)
Defined in: [packages/form-core/src/FormApi.ts:1226](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1226)

Inserts a value into an array field at the specified index, shifting the subsequent values to the right.

Expand Down Expand Up @@ -279,7 +279,7 @@ Inserts a value into an array field at the specified index, shifting the subsequ
mount(): () => void
```

Defined in: [packages/form-core/src/FormApi.ts:595](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L595)
Defined in: [packages/form-core/src/FormApi.ts:607](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L607)

#### Returns

Expand All @@ -301,7 +301,7 @@ moveFieldValues<TField>(
opts?): void
```

Defined in: [packages/form-core/src/FormApi.ts:1332](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1332)
Defined in: [packages/form-core/src/FormApi.ts:1344](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1344)

Moves the value at the first specified index to the second specified index within an array field.

Expand Down Expand Up @@ -342,7 +342,7 @@ pushFieldValue<TField>(
opts?): void
```

Defined in: [packages/form-core/src/FormApi.ts:1196](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1196)
Defined in: [packages/form-core/src/FormApi.ts:1208](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1208)

Pushes a value into an array field.

Expand Down Expand Up @@ -379,7 +379,7 @@ removeFieldValue<TField>(
opts?): Promise<void>
```

Defined in: [packages/form-core/src/FormApi.ts:1267](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1267)
Defined in: [packages/form-core/src/FormApi.ts:1279](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1279)

Removes a value from an array field at the specified index.

Expand Down Expand Up @@ -417,7 +417,7 @@ replaceFieldValue<TField>(
opts?): Promise<void>
```

Defined in: [packages/form-core/src/FormApi.ts:1241](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1241)
Defined in: [packages/form-core/src/FormApi.ts:1253](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1253)

Replaces a value into an array field at the specified index.

Expand Down Expand Up @@ -455,7 +455,7 @@ Replaces a value into an array field at the specified index.
reset(values?, opts?): void
```

Defined in: [packages/form-core/src/FormApi.ts:656](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L656)
Defined in: [packages/form-core/src/FormApi.ts:668](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L668)

Resets the form state to the default values.
If values are provided, the form will be reset to those values instead and the default values will be updated.
Expand Down Expand Up @@ -488,7 +488,7 @@ Optional options to control the reset behavior.
resetFieldMeta<TField>(fieldMeta): Record<TField, FieldMeta>
```

Defined in: [packages/form-core/src/FormApi.ts:1128](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1128)
Defined in: [packages/form-core/src/FormApi.ts:1140](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1140)

#### Type Parameters

Expand All @@ -512,7 +512,7 @@ Defined in: [packages/form-core/src/FormApi.ts:1128](https://github.com/TanStack
setErrorMap(errorMap): void
```

Defined in: [packages/form-core/src/FormApi.ts:1356](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1356)
Defined in: [packages/form-core/src/FormApi.ts:1368](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1368)

Updates the form's errorMap

Expand All @@ -534,7 +534,7 @@ Updates the form's errorMap
setFieldMeta<TField>(field, updater): void
```

Defined in: [packages/form-core/src/FormApi.ts:1110](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1110)
Defined in: [packages/form-core/src/FormApi.ts:1122](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1122)

Updates the metadata of the specified field.

Expand Down Expand Up @@ -567,7 +567,7 @@ setFieldValue<TField>(
opts?): void
```

Defined in: [packages/form-core/src/FormApi.ts:1152](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1152)
Defined in: [packages/form-core/src/FormApi.ts:1164](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1164)

Sets the value of the specified field and optionally updates the touched state.

Expand Down Expand Up @@ -605,7 +605,7 @@ swapFieldValues<TField>(
opts?): void
```

Defined in: [packages/form-core/src/FormApi.ts:1306](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1306)
Defined in: [packages/form-core/src/FormApi.ts:1318](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L1318)

Swaps the values at the specified indices within an array field.

Expand Down Expand Up @@ -643,7 +643,7 @@ Swaps the values at the specified indices within an array field.
update(options?): void
```

Defined in: [packages/form-core/src/FormApi.ts:612](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L612)
Defined in: [packages/form-core/src/FormApi.ts:624](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L624)

Updates the form options and form state.

Expand All @@ -665,7 +665,7 @@ Updates the form options and form state.
validateAllFields(cause): Promise<ValidationError[]>
```

Defined in: [packages/form-core/src/FormApi.ts:682](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L682)
Defined in: [packages/form-core/src/FormApi.ts:694](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L694)

Validates form and all fields in using the correct handlers for a given validation cause.

Expand All @@ -690,7 +690,7 @@ validateArrayFieldsStartingFrom<TField>(
cause): Promise<ValidationError[]>
```

Defined in: [packages/form-core/src/FormApi.ts:710](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L710)
Defined in: [packages/form-core/src/FormApi.ts:722](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L722)

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.

Expand Down Expand Up @@ -726,7 +726,7 @@ validateField<TField>(field, cause):
| Promise<ValidationError[]>
```

Defined in: [packages/form-core/src/FormApi.ts:749](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L749)
Defined in: [packages/form-core/src/FormApi.ts:761](https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts#L761)

Validates a specified field in the form using the correct handlers for a given validation type.

Expand Down
16 changes: 14 additions & 2 deletions packages/form-core/src/FormApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,10 @@ export class FormApi<
fieldName as never
] as FieldMetaBase | undefined

let fieldErrors =
prevVal?.[fieldName as never as keyof typeof prevVal]?.errors
const prevFieldInfo =
prevVal?.[fieldName as never as keyof typeof prevVal]

let fieldErrors = prevFieldInfo?.errors
if (!prevBaseVal || currBaseVal.errorMap !== prevBaseVal.errorMap) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
fieldErrors = Object.values(currBaseVal.errorMap ?? {}).filter(
Expand All @@ -428,6 +430,16 @@ export class FormApi<
// As a primitive, we don't need to aggressively persist the same referencial value for performance reasons
const isFieldPristine = !currBaseVal.isDirty

if (
prevFieldInfo &&
prevFieldInfo.isPristine === isFieldPristine &&
prevFieldInfo.errors === fieldErrors &&
currBaseVal === prevBaseVal
) {
fieldMeta[fieldName] = prevFieldInfo
continue
}

fieldMeta[fieldName] = {
...currBaseVal,
errors: fieldErrors,
Expand Down
62 changes: 62 additions & 0 deletions packages/react-form/tests/useField.test.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react-compiler/react-compiler */
import { describe, expect, it, vi } from 'vitest'
import { render, waitFor } from '@testing-library/react'
import { userEvent } from '@testing-library/user-event'
Expand Down Expand Up @@ -1068,4 +1069,65 @@ describe('useField', () => {
await user.click(getByText('Add person'))
expect(getByText(`["Test"]`)).toBeInTheDocument()
})

it('should not rerender unrelated fields', async () => {
const renderCount = {
field1: 0,
field2: 0,
}

function Comp() {
const form = useForm({
defaultValues: {
field1: '',
field2: '',
},
})

return (
<>
<form.Field name="field1">
{(field) => {
renderCount.field1++
return (
<input
data-testid="field1"
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
/>
)
}}
</form.Field>
<form.Field name="field2">
{(field) => {
renderCount.field2++
return (
<input
data-testid="field2"
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
/>
)
}}
</form.Field>
</>
)
}

const { getByTestId } = render(
<StrictMode>
<Comp />
</StrictMode>,
)

const field1InitialRender = renderCount.field1
const field2InitialRender = renderCount.field2

await user.type(getByTestId('field1'), 'test')

// field1 should have rerendered
expect(renderCount.field1).toBeGreaterThan(field1InitialRender)
// field2 should not have rerendered
expect(renderCount.field2).toBe(field2InitialRender)
})
})
Loading