// Query-owned RSC pattern. // Assumes your router context provides a queryClient for SSR prefetch. import type { ReactNode } from 'react' import { createFileRoute } from '@tanstack/react-router' import { createServerFn } from '@tanstack/react-start' import { CompositeComponent, createCompositeComponent, } from '@tanstack/react-start/rsc' import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query' import { z } from 'zod' // Replace with your own data layer declare const db: { posts: { findById(postId: string): Promise<{ id: string title: string body: string }> update( postId: string, patch: { title?: string; body?: string }, ): Promise } } const getPostRsc = createServerFn({ method: 'GET' }) .inputValidator(z.object({ postId: z.string() })) .handler(async ({ data }) => { const post = await db.posts.findById(data.postId) const src = await createCompositeComponent<{ renderActions?: (args: { postId: string }) => ReactNode }>((props) => (

{post.title}

{post.body}

{props.renderActions?.({ postId: post.id })}
)) return { src } }) const updatePost = createServerFn({ method: 'POST' }) .inputValidator( z.object({ postId: z.string(), title: z.string().optional(), body: z.string().optional(), }), ) .handler(async ({ data }) => { await db.posts.update(data.postId, { title: data.title, body: data.body, }) }) const postQueryOptions = (postId: string) => ({ queryKey: ['post-rsc', postId], structuralSharing: false, queryFn: () => getPostRsc({ data: { postId } }), staleTime: 5 * 60 * 1000, }) export const Route = createFileRoute('/posts/$postId')({ loader: async ({ context, params }) => { await context.queryClient.ensureQueryData(postQueryOptions(params.postId)) }, component: PostPage, }) function PostPage() { const { postId } = Route.useParams() const queryClient = useQueryClient() const { data } = useSuspenseQuery(postQueryOptions(postId)) const handleRename = async () => { await updatePost({ data: { postId, title: 'Updated title' } }) await queryClient.invalidateQueries({ queryKey: ['post-rsc', postId] }) } return ( ( )} /> ) }