Skip to content
Open
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
2 changes: 1 addition & 1 deletion docs/router/integrations/query.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export const Route = createFileRoute('/user/$id')({

## Redirect handling

If a query or mutation throws a `redirect(...)`, the integration intercepts it on the client and performs a router navigation.
If a query or mutation throws a `redirect(...)`, the integration intercepts it on the client and performs a router navigation. You do not need to individually wrap [server functions](/start/latest/docs/framework/react/guide/server-functions) in `useServerFn` if they are called in a `queryFn` or `mutationFn`.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the router docs, whereas useServerFn is from start. this crossover is a bit unfortunate here, maybe we should instead document the query integration in start separately?

cc @LadyBluenotes


- Enabled by default
- Disable with `handleRedirects: false` if you need custom handling
Expand Down
5 changes: 4 additions & 1 deletion docs/start/framework/react/guide/server-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ function PostList() {
}
```

> [!NOTE]
> If you use TanStack Query with the `@tanstack/react-router-ssr-query` integration package, wrapping server functions called in `queryFn` or `mutationFn` with `useServerFn` is not required. See the [Query integration guide](/router/latest/docs/integrations/query#redirect-handling) for more details.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
## File Organization

For larger applications, consider organizing server-side code into separate files. Here's one approach:
Expand Down Expand Up @@ -257,7 +260,7 @@ export const looseOutputServerFn = createServerFn({

## Error Handling & Redirects

Server functions can throw errors, redirects, and not-found responses that are handled automatically when called from route lifecycles or components using `useServerFn()`.
Server functions can throw errors, redirects, and not-found responses that are handled automatically when called from route lifecycles, components using `useServerFn()`, or inside TanStack Query `queryFn` and `mutationFn` functions when the [`@tanstack/react-router-ssr-query` integration package](/router/latest/docs/integrations/query) is used.

### Basic Errors

Expand Down
7 changes: 4 additions & 3 deletions docs/start/framework/react/guide/tanstack-query.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ Both calls use the same query key and options. The loader populates the request'

For a parameterized resource, include its identity in the key, such as `['post', postId]`. If search values affect the result, validate them and include them in both `loaderDeps` and the query key. Keep secrets out of keys and serialized query data.

Note that if you are using server functions and you have the [integration](#install-and-create-a-queryclient-per-router) installed, you do not need to use `useServerFn` to properly handle thrown errors or redirects. Simply call the server function in a `queryFn` or `mutationFn` normally.

## Await critical data and stream secondary data

Await queries that determine the page's main content, title, authorization, redirects, or whether it exists. Return title and description data from the loader when a route's `head` needs them, as the example's post route does.
Expand All @@ -95,13 +97,12 @@ The example's existing `/deferred` route shows a separate Suspense boundary. See

## Invalidate Query after a server mutation

The preference example validates the display name and writes its cookie inside a POST server function. Its `src/start.ts` enables Start's CSRF middleware for server-function requests. The component calls that function through `useServerFn`, then invalidates the query that reads the cookie:
The preference example validates the display name and writes its cookie inside a POST server function. Its `src/start.ts` enables Start's CSRF middleware for server-function requests. The component calls that function, then invalidates the query that reads the cookie:

```tsx
const queryClient = useQueryClient()
const save = useServerFn(saveReaderName)
const mutation = useMutation({
mutationFn: (name: string) => save({ data: name }),
mutationFn: (name: string) => saveReaderName({ data: name }),
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: readerNameOptions.queryKey }),
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
useSuspenseQuery,
} from '@tanstack/react-query'
import { createFileRoute, useHydrated } from '@tanstack/react-router'
import { useServerFn } from '@tanstack/react-start'
import { readerNameOptions, saveReaderName } from '../utils/preferences'

export const Route = createFileRoute('/preferences')({
Expand All @@ -19,10 +18,9 @@ export const Route = createFileRoute('/preferences')({
function Preferences() {
const { data: name } = useSuspenseQuery(readerNameOptions)
const queryClient = useQueryClient()
const save = useServerFn(saveReaderName)
const hydrated = useHydrated()
const mutation = useMutation({
mutationFn: (name: string) => save({ data: name }),
mutationFn: (name: string) => saveReaderName({ data: name }),
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: readerNameOptions.queryKey }),
})
Expand Down