Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 9 additions & 0 deletions .changeset/use-selector-export.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@tanstack/react-form': patch
'@tanstack/preact-form': patch
'@tanstack/vue-form': patch
'@tanstack/solid-form': patch
'@tanstack/svelte-form': patch
---

Re-export `useSelector` from TanStack Store adapters and document migration from deprecated `useStore` (fixes #2203).
16 changes: 9 additions & 7 deletions docs/framework/preact/guides/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,14 @@ function App() {

## Reactivity

`@tanstack/preact-form` offers various ways to subscribe to form and field state changes, most notably the `useStore(form.store)` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary.
`@tanstack/preact-form` offers various ways to subscribe to form and field state changes, most notably the `useSelector(form.store)` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

Example:

```tsx
const firstName = useStore(form.store, (state) => state.values.firstName)
import { useSelector } from '@tanstack/preact-form'

const firstName = useSelector(form.store, (state) => state.values.firstName)
//...
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
Expand All @@ -253,17 +255,17 @@ const firstName = useStore(form.store, (state) => state.values.firstName)
/>
```

It is important to remember that while the `useStore` hook's `selector` prop is optional, it is strongly recommended to provide one, as omitting it will result in unnecessary re-renders.
It is important to remember that while the `useSelector` hook's `selector` prop is optional, it is strongly recommended to provide one, as omitting it will result in unnecessary re-renders.

```tsx
// Correct use
const firstName = useStore(form.store, (state) => state.values.firstName)
const errors = useStore(form.store, (state) => state.errorMap)
const firstName = useSelector(form.store, (state) => state.values.firstName)
const errors = useSelector(form.store, (state) => state.errorMap)
// Incorrect use
const store = useStore(form.store)
const store = useSelector(form.store)
```

Note: The usage of the `useField` hook to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `useStore(form.store)` instead.
Note: The usage of the `useField` hook to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `useSelector(form.store)` instead.

## Listeners

Expand Down
4 changes: 2 additions & 2 deletions docs/framework/preact/guides/form-composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,9 @@ const FieldGroupPasswordFields = withFieldGroup({
// Internally, you will have access to a `group` instead of a `form`
render: function Render({ group, title }) {
// access reactive values using the group store
const password = useStore(group.store, (state) => state.values.password)
const password = useSelector(group.store, (state) => state.values.password)
// or the form itself
const isSubmitting = useStore(
const isSubmitting = useSelector(
group.form.store,
(state) => state.isSubmitting,
)
Expand Down
20 changes: 9 additions & 11 deletions docs/framework/preact/guides/reactivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,24 @@ title: Reactivity

Tanstack Form doesn't cause re-renders when interacting with the form. So, you might find yourself trying to use a form or field state value without success.

If you would like to access reactive values, you will need to subscribe to them using one of two methods: `useStore` or the `form.Subscribe` component.
If you would like to access reactive values, you will need to subscribe to them using one of two methods: `useSelector` or the `form.Subscribe` component.

Some uses for these subscriptions are rendering up-to-date field values, determining what to render based on a condition, or using field values inside the logic of your component.

> For situations where you want to "react" to triggers, check out the [listener](./listeners.md) API.

## useStore
## useSelector

The `useStore` hook is perfect when you need to access form values within the logic of your component. `useStore` takes two parameters. First, the form store. Second, a selector to specify the piece of the form you wish to subscribe to.
Import `useSelector` from `@tanstack/preact-form` when you need form values inside component logic.

```tsx
const firstName = useStore(form.store, (state) => state.values.firstName)
const errors = useStore(form.store, (state) => state.errorMap)
```

You can access any piece of the form state in the selector.
import { useSelector } from '@tanstack/preact-form'

> Note, that `useStore` will cause a whole component re-render whenever the value subscribed to changes.
const firstName = useSelector(form.store, (state) => state.values.firstName)
const errors = useSelector(form.store, (state) => state.errorMap)
```

While it IS possible to omit the selector, resist the urge as omitting it would result in many unnecessary re-renders whenever any of the form state changes.
> **Migration:** `useStore` is still exported but deprecated; use `useSelector` with the same arguments.

## form.Subscribe

Expand All @@ -49,4 +47,4 @@ 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 `useStore` 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 `useStore` is the better choice.
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.
2 changes: 1 addition & 1 deletion docs/framework/preact/guides/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export default function App() {

// Subscribe to the form's `errorMap` so that updates to it will cause re-renders
// Alternatively, you can use `form.Subscribe`
const formErrorMap = useStore(form.store, (state) => state.errorMap)
const formErrorMap = useSelector(form.store, (state) => state.errorMap)

return (
<div>
Expand Down
1 change: 1 addition & 0 deletions docs/framework/preact/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ title: "@tanstack/preact-form"
- [Field](variables/Field.md)
- [FormGroup](variables/FormGroup.md)
- [useIsomorphicLayoutEffect](variables/useIsomorphicLayoutEffect.md)
- [useSelector](variables/useSelector.md)
- [~~useStore~~](variables/useStore.md)

## Functions
Expand Down
25 changes: 25 additions & 0 deletions docs/framework/preact/reference/variables/useSelector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
id: useSelector
title: useSelector
---

# Variable: useSelector()

```ts
const useSelector: <TSource, TSelected>(source, selector?, options?) => TSelected;
```

Re-exported from `@tanstack/preact-store`. Use this hook to subscribe to slices of `form.store` inside component logic.

## Example

```tsx
import { useForm, useSelector } from '@tanstack/preact-form'

const form = useForm({ /* ... */ })
const firstName = useSelector(form.store, (state) => state.values.firstName)
```

## Migration from useStore

`useStore` is deprecated; import `useSelector` from `@tanstack/preact-form` instead. The API is the same aside from optional `options.compare` instead of a bare `compare` third argument.
6 changes: 5 additions & 1 deletion docs/framework/preact/reference/variables/useStore.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,8 @@ const count = useStore(counterStore, (state) => state.count)

## Deprecated

Use `useSelector` instead.
Use [`useSelector`](useSelector.md) instead. You can import it from `@tanstack/preact-form`:

```tsx
import { useSelector } from '@tanstack/preact-form'
```
18 changes: 11 additions & 7 deletions docs/framework/react/guides/basic-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,14 @@ function App() {

## Reactivity

`@tanstack/react-form` offers various ways to subscribe to form and field state changes, most notably the `useStore(form.store)` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary.
`@tanstack/react-form` offers various ways to subscribe to form and field state changes, most notably the `useSelector(form.store, …)` hook and the `form.Subscribe` component. These methods allow you to optimize your form's rendering performance by only updating components when necessary.

Example:

```tsx
const firstName = useStore(form.store, (state) => state.values.firstName)
import { useSelector } from '@tanstack/react-form'

const firstName = useSelector(form.store, (state) => state.values.firstName)
//...
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
Expand All @@ -253,17 +255,19 @@ const firstName = useStore(form.store, (state) => state.values.firstName)
/>
```

It is important to remember that while the `useStore` hook's `selector` prop is optional, it is strongly recommended to provide one, as omitting it will result in unnecessary re-renders.
It is important to remember that while the `useSelector` hook's selector argument is optional, it is strongly recommended to provide one, as omitting it will result in unnecessary re-renders.

```tsx
import { useSelector } from '@tanstack/react-form'

// Correct use
const firstName = useStore(form.store, (state) => state.values.firstName)
const errors = useStore(form.store, (state) => state.errorMap)
const firstName = useSelector(form.store, (state) => state.values.firstName)
const errors = useSelector(form.store, (state) => state.errorMap)
// Incorrect use
const store = useStore(form.store)
const store = useSelector(form.store)
```

Note: The usage of the `useField` hook to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `useStore(form.store)` instead.
Note: The usage of the `useField` hook to achieve reactivity is discouraged since it is designed to be used thoughtfully within the `form.Field` component. You might want to use `useSelector(form.store, …)` instead.

## Listeners

Expand Down
4 changes: 2 additions & 2 deletions docs/framework/react/guides/form-composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,9 @@ const FieldGroupPasswordFields = withFieldGroup({
// Internally, you will have access to a `group` instead of a `form`
render: function Render({ group, title }) {
// access reactive values using the group store
const password = useStore(group.store, (state) => state.values.password)
const password = useSelector(group.store, (state) => state.values.password)
// or the form itself
const isSubmitting = useStore(
const isSubmitting = useSelector(
group.form.store,
(state) => state.isSubmitting,
)
Expand Down
18 changes: 11 additions & 7 deletions docs/framework/react/guides/reactivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,31 @@ title: Reactivity

Tanstack Form doesn't cause re-renders when interacting with the form. So, you might find yourself trying to use a form or field state value without success.

If you would like to access reactive values, you will need to subscribe to them using one of two methods: `useStore` or the `form.Subscribe` component.
If you would like to access reactive values, you will need to subscribe to them using one of two methods: `useSelector` or the `form.Subscribe` component.

Some uses for these subscriptions are rendering up-to-date field values, determining what to render based on a condition, or using field values inside the logic of your component.

> For situations where you want to "react" to triggers, check out the [listener](./listeners.md) API.

## useStore
## useSelector

The `useStore` hook is perfect when you need to access form values within the logic of your component. `useStore` takes two parameters. First, the form store. Second, a selector to specify the piece of the form you wish to subscribe to.
The `useSelector` hook is perfect when you need to access form values within the logic of your component. Import it from `@tanstack/react-form`. It takes the form store as its first argument and a selector as its second.

```tsx
const firstName = useStore(form.store, (state) => state.values.firstName)
const errors = useStore(form.store, (state) => state.errorMap)
import { useSelector } from '@tanstack/react-form'

const firstName = useSelector(form.store, (state) => state.values.firstName)
const errors = useSelector(form.store, (state) => state.errorMap)
```

You can access any piece of the form state in the selector.

> Note, that `useStore` will cause a whole component re-render whenever the value subscribed to changes.
> Note, that `useSelector` will cause a whole component re-render whenever the value subscribed to changes.

While it IS possible to omit the selector, resist the urge as omitting it would result in many unnecessary re-renders whenever any of the form state changes.

> **Migration:** `useStore` is still exported but deprecated (it is an alias from `@tanstack/react-store`). Replace `useStore` with `useSelector` — same arguments, or pass `{ compare }` as the third argument instead of a bare `compare` function.

## form.Subscribe

The `form.Subscribe` component is best suited when you need to react to something within the UI of your component. For example, showing or hiding UI based on the value of a form field.
Expand All @@ -49,4 +53,4 @@ 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 `useStore` 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 `useStore` is the better choice.
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.
12 changes: 6 additions & 6 deletions docs/framework/react/guides/ssr.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ import { createFileRoute } from '@tanstack/react-router'
import {
mergeForm,
useForm,
useStore,
useSelector,
useTransform,
} from '@tanstack/react-form-start'

Expand All @@ -128,7 +128,7 @@ function Home() {
transform: useTransform((baseForm) => mergeForm(baseForm, state), [state]),
})

const formErrors = useStore(form.store, (formState) => formState.errors)
const formErrors = useSelector(form.store, (formState) => formState.errors)

return (
<form action={handleForm.url} method="post" encType={'multipart/form-data'}>
Expand Down Expand Up @@ -259,7 +259,7 @@ import {
initialFormState,
mergeForm,
useForm,
useStore,
useSelector,
useTransform,
} from '@tanstack/react-form-nextjs'
import someAction from './action'
Expand All @@ -273,7 +273,7 @@ export const ClientComp = () => {
transform: useTransform((baseForm) => mergeForm(baseForm, state!), [state]),
})

const formErrors = useStore(form.store, (formState) => formState.errors)
const formErrors = useSelector(form.store, (formState) => formState.errors)

return (
<form action={action as never} onSubmit={() => form.handleSubmit()}>
Expand Down Expand Up @@ -414,7 +414,7 @@ import {
mergeForm,
useActionData,
useForm,
useStore,
useSelector,
useTransform,
} from '@tanstack/react-form'
import {
Expand Down Expand Up @@ -443,7 +443,7 @@ export default function Index() {
),
})

const formErrors = useStore(form.store, (formState) => formState.errors)
const formErrors = useSelector(form.store, (formState) => formState.errors)

return (
<Form method="post" onSubmit={() => form.handleSubmit()}>
Expand Down
2 changes: 1 addition & 1 deletion docs/framework/react/guides/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export default function App() {

// Subscribe to the form's `errorMap` so that updates to it will cause re-renders
// Alternatively, you can use `form.Subscribe`
const formErrorMap = useStore(form.store, (state) => state.errorMap)
const formErrorMap = useSelector(form.store, (state) => state.errorMap)

return (
<div>
Expand Down
1 change: 1 addition & 0 deletions docs/framework/react/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ title: "@tanstack/react-form"
- [Field](variables/Field.md)
- [FormGroup](variables/FormGroup.md)
- [useIsomorphicLayoutEffect](variables/useIsomorphicLayoutEffect.md)
- [useSelector](variables/useSelector.md)
- [~~useStore~~](variables/useStore.md)

## Functions
Expand Down
53 changes: 53 additions & 0 deletions docs/framework/react/reference/variables/useSelector.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
id: useSelector
title: useSelector
---

# Variable: useSelector()

```ts
const useSelector: <TSource, TSelected>(source, selector?, options?) => TSelected;
```

Re-exported from `@tanstack/react-store`. Use this hook to subscribe to slices of `form.store` (or any TanStack Store source) inside component logic.

## Parameters

### source

A store or atom with `get()` and `subscribe()`.

### selector?

`(snapshot) => TSelected` — strongly recommended; omitting it subscribes to the entire store and may cause extra re-renders.

### options?

- **compare?** — `(a, b) => boolean` custom equality check (defaults to `===`).

## Returns

`TSelected`

## Example

```tsx
import { useForm, useSelector } from '@tanstack/react-form'

const form = useForm({ /* ... */ })
const firstName = useSelector(form.store, (state) => state.values.firstName)
```

## Migration from useStore

`useStore` is a deprecated alias of `useSelector` with the same signature (the third argument is `compare` on `useStore`, or `options.compare` on `useSelector`):

```tsx
// Before
import { useStore } from '@tanstack/react-form'
const firstName = useStore(form.store, (state) => state.values.firstName)

// After
import { useSelector } from '@tanstack/react-form'
const firstName = useSelector(form.store, (state) => state.values.firstName)
```
6 changes: 5 additions & 1 deletion docs/framework/react/reference/variables/useStore.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,8 @@ const count = useStore(counterStore, (state) => state.count)

## Deprecated

Use `useSelector` instead.
Use [`useSelector`](useSelector.md) instead. You can import it from `@tanstack/react-form`:

```tsx
import { useSelector } from '@tanstack/react-form'
```
Loading