diff --git a/docs/framework/react/guides/form-composition.md b/docs/framework/react/guides/form-composition.md index cf2db1cc19..0e7513aa47 100644 --- a/docs/framework/react/guides/form-composition.md +++ b/docs/framework/react/guides/form-composition.md @@ -55,23 +55,29 @@ Once this scaffolding is in place, you can start adding custom field and form co > Note: the `useFieldContext` must be the same one exported from your custom form context ```tsx +import { useSelector } from '@tanstack/react-form' import { useFieldContext } from './form-context.tsx' export function TextField({ label }: { label: string }) { // The `Field` infers that it should have a `value` type of `string` const field = useFieldContext() + const errors = useSelector(field.store, (state) => state.meta.errors) return ( ) } ``` +To keep a field component in sync with meta such as `errors`, read it with `useSelector`. See [Reactivity](./reactivity.md#field-state) for details. + You're then able to register this component with your form hook. ```tsx diff --git a/docs/framework/react/guides/reactivity.md b/docs/framework/react/guides/reactivity.md index d85b6bdbec..c857b0a9d8 100644 --- a/docs/framework/react/guides/reactivity.md +++ b/docs/framework/react/guides/reactivity.md @@ -54,3 +54,18 @@ The `form.Subscribe` component is best suited when you need to react to somethin > The `form.Subscribe` component doesn't trigger component-level re-renders. Anytime the value subscribed to changes, only the `form.Subscribe` component re-renders. The choice between whether to use `useSelector` or `form.Subscribe` mainly boils down to your use case. If you're aiming for direct UI updates based on form state, use `form.Subscribe` for its optimization perks. And if you need the reactivity within the logic, then `useSelector` is the better choice. + +## Field state + +Inside a field, you don't need `useSelector` or `form.Subscribe` to read the field's own state. `form.Field` subscribes to its field for you: its render function runs again whenever the field's value or meta (such as `isTouched`, `isDirty`, `errors` or `isValidating`) changes, so `field.state.value` and `field.state.meta` are up to date there. + +> [!NOTE] +> Array fields (`mode="array"`) are an exception: to avoid re-rendering the whole list on every keystroke, they don't re-render when a value inside one of their items changes. Render those values with their own `form.Field` instead. + +Field components that read the field with `useFieldContext`, as shown in [Form Composition](./form-composition.md#pre-bound-field-components), live outside that render function. In those components, read field state such as `meta` with `useSelector` and the field's store: + +```tsx +import { useSelector } from '@tanstack/react-form' + +const errors = useSelector(field.store, (state) => state.meta.errors) +```