DEV Community

Alex Spinov
Alex Spinov

Posted on

TanStack Router Has a Free API You're Not Using

TanStack Router is the fully type-safe React router that makes React Router look like it's from 2015. Search params, loaders, and route context — all with full TypeScript inference.

The Free APIs You're Missing

1. Type-Safe Search Params — No More useSearchParams

import { createFileRoute } from "@tanstack/react-router";
import { z } from "zod";

export const Route = createFileRoute("/products")(
  validateSearch: z.object({
    page: z.number().default(1),
    sort: z.enum(["price", "name", "date"]).default("date"),
    category: z.string().optional(),
    minPrice: z.number().optional(),
  }),
});

// In component — fully typed!
function ProductsPage() {
  const { page, sort, category } = Route.useSearch();
  const navigate = Route.useNavigate();

  return (
    <button onClick={() => navigate({ search: { page: page + 1 } })}>
      Next Page
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

2. Route Loaders — Data Fetching Before Render

export const Route = createFileRoute("/users/$userId")({
  loader: async ({ params }) => {
    const user = await fetchUser(params.userId);
    const posts = await fetchPosts(params.userId);
    return { user, posts };
  },
  component: UserPage,
});

function UserPage() {
  const { user, posts } = Route.useLoaderData();
  // Data is already loaded — no loading states!
  return <div>{user.name} has {posts.length} posts</div>;
}
Enter fullscreen mode Exit fullscreen mode

3. Route Context — Dependency Injection for Routes

const router = createRouter({
  routeTree,
  context: {
    auth: undefined!, // Will be provided
    queryClient: undefined!,
  },
});

export const Route = createFileRoute("/admin")({
  beforeLoad: ({ context }) => {
    if (!context.auth.isAdmin) throw redirect({ to: "/login" });
  },
  loader: ({ context }) => {
    return context.queryClient.ensureQueryData(adminStatsQuery);
  },
});
Enter fullscreen mode Exit fullscreen mode

4. Pending UI — Automatic Loading States

function App() {
  return (
    <RouterProvider
      router={router}
      defaultPendingComponent={() => <Spinner />}
      defaultErrorComponent={({ error }) => <ErrorPage error={error} />}
      defaultNotFoundComponent={() => <NotFound />}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

5. Path Params — Fully Typed

// routes/users/$userId/posts/$postId.tsx
export const Route = createFileRoute("/users/$userId/posts/$postId")({
  component: PostPage,
});

function PostPage() {
  const { userId, postId } = Route.useParams();
  // Both are typed as string — no manual parsing
}

// Navigation is type-safe too
<Link to="/users/$userId/posts/$postId" params={{ userId: "123", postId: "456" }}>
  View Post
</Link>
Enter fullscreen mode Exit fullscreen mode

Getting Started

npm install @tanstack/react-router
Enter fullscreen mode Exit fullscreen mode

Need data from any website delivered as clean JSON? I build production web scrapers that handle anti-bot, proxies, and rate limits. 77 scrapers running in production. Email me: Spinov001@gmail.com

Check out my awesome-web-scraping list for the best scraping tools and resources.

Top comments (0)