Skip to content
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
6 changes: 6 additions & 0 deletions docs/framework/react/guides/form-composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>()
const errors = useSelector(field.store, (state) => state.meta.errors)
return (
<label>
<span>{label}</span>
<input
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
onBlur={field.handleBlur}
/>
{errors.length > 0 && <em role="alert">{errors.join(', ')}</em>}
</label>
)
}
```

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
Expand Down
15 changes: 15 additions & 0 deletions docs/framework/react/guides/reactivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Comment thread
dgesteves marked this conversation as resolved.

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)
```
Loading