Route Loaders
Prefetch data before components mount using TanStack Router or React Router loaders
Factory functions let you create reusable, pre-configured query and mutation objects. Unlike hooks which are created fresh on each render, factories create stable objects you can use across loaders, components, and utilities.
Route Loaders
Prefetch data before components mount using TanStack Router or React Router loaders
Centralized Config
Define select, staleTime, invalidateQueries once — use everywhere
Cache Access
Read/invalidate cache outside of React components
Type Safety
Get consistent types across your entire app
import { // Query factories createQuery, createQueryFactory, createSuspenseQuery, createSuspenseQueryFactory,
// Mutation factory createMutation,
// Infinite query factories createInfiniteQuery, createInfiniteQueryFactory, createSuspenseInfiniteQuery, createSuspenseInfiniteQueryFactory,} from "@ic-reactor/react"| Factory | Suspense | Dynamic Args | Use Case |
|---|---|---|---|
createQuery |
❌ | Via Factory variant |
Standard queries with enabled |
createSuspenseQuery |
✅ | Via Factory variant |
Suspense-based loading |
createMutation |
N/A | Args at call time | State mutations |
createInfiniteQuery |
❌ | Via Factory variant |
Pagination/infinite scroll |
createSuspenseInfiniteQuery |
✅ | Via Factory variant |
Suspense pagination |
Organize all your queries in a dedicated file:
import { createQueryFactory, createMutation } from "@ic-reactor/react"import { backend } from "../reactor"
// Query factoriesexport const getUserQuery = createQueryFactory(backend, { functionName: "get_user", staleTime: 5 * 60 * 1000,})
export const getPostsQuery = createQueryFactory(backend, { functionName: "get_posts",})
// Mutation factoriesexport const createPostMutation = createMutation(backend, { functionName: "create_post", // A query factory covers every query it returns, whatever the args invalidateQueries: [getPostsQuery],})
// Query keys, for QueryClient calls of your ownexport const queryKeys = { users: () => getUserQuery.getQueryKey(), // every get_user query userById: (id: string) => getUserQuery([id]).getQueryKey(), posts: () => getPostsQuery.getQueryKey(),}import { createFileRoute } from "@tanstack/react-router"import { getUserQuery } from "../queries"
export const Route = createFileRoute("/users/$userId")({ // Prefetch in loader loader: async ({ params }) => { return { user: await getUserQuery([params.userId]).fetch() } },
component: UserPage,})
function UserPage() { // Data already loaded, instant render const { data } = getUserQuery([Route.useParams().userId]).useQuery() return <Profile user={data} />}import { useLoaderData, type LoaderFunctionArgs } from "react-router-dom"import { getUserQuery } from "../queries"
export async function loader({ params }: LoaderFunctionArgs) { if (!params.userId) throw new Response("Not Found", { status: 404 }) return { user: await getUserQuery([params.userId]).fetch() }}
export function UserPage() { const { user } = useLoaderData() as Awaited<ReturnType<typeof loader>> return <Profile user={user} />}