DEV Community

Cover image for Introducing Tanstack Router
Kevin Toshihiro Uehara
Kevin Toshihiro Uehara

Posted on

9 1

Introducing Tanstack Router

Hi Folks! Are you all right? everything in peace? Everything calm? I hope you are well!

Today I'm gonna talk about the Tanstack Router!
Tanstack Router is a fully type-safe router with built-in data fetching, stale-while revalidate caching and first-class search-param APIs. Tanstack router was created by same creators of React Query.

More details you can find on documentation

So let's hands on creating a project using tanstack router, tanstack query (React query) with React and Typescript.

First let's create our project using Vite with the command:

npm create vite@latest tanstack-router -- --template react-ts
Enter fullscreen mode Exit fullscreen mode

Open in your preferred IDE, and install the dependecies using

yarn
Enter fullscreen mode Exit fullscreen mode

Now let's add our dependencies:

yarn add @tanstack/react-router @tanstack/react-query
Enter fullscreen mode Exit fullscreen mode

Add the dev dependecies

yarn add -D @tanstack/router-plugin @tanstack/router-devtools
Enter fullscreen mode Exit fullscreen mode

Delete the App.tsx

Now change the main.tsx by:

import { StrictMode } from "react";
import ReactDOM from "react-dom/client";
import { RouterProvider, createRouter } from "@tanstack/react-router";

// Import the generated route tree
import { routeTree } from "./routeTree.gen";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

// Create a new router instance
const router = createRouter({ routeTree });

// Register the router instance for type safety
declare module "@tanstack/react-router" {
  interface Register {
    router: typeof router;
  }
}

const queryClient = new QueryClient();

// Render the app
const rootElement = document.getElementById("root")!;
if (!rootElement.innerHTML) {
  const root = ReactDOM.createRoot(rootElement);
  root.render(
    <StrictMode>
      <QueryClientProvider client={queryClient}>
        <RouterProvider router={router} />
      </QueryClientProvider>
    </StrictMode>
  );
}

Enter fullscreen mode Exit fullscreen mode

Here we are creating the router instance of Tanstack router and registering the types. Also, I'm adding the Tanstack query (React Query) provider.

The file ./routeTree.gen it will be generated automatically for you. So don't change this file because it will be overwrited.

Now create the folder routes inside of src. Create the file __root.tsx which will contain the routes.

src/routes/__root.tsx

import { createRootRoute, Link, Outlet } from "@tanstack/react-router";
import { TanStackRouterDevtools } from "@tanstack/router-devtools";

export const Route = createRootRoute({
  component: () => (
    <>
      <div className="p-2 flex gap-2">
        <Link to="/" className="[&.active]:font-bold">
          Home
        </Link>{" "}
        <Link to="/about" className="[&.active]:font-bold">
          About
        </Link>
        <Link to="/users" className="[&.active]:font-bold">
          {" "}
          Users
        </Link>
      </div>
      <hr />
      <Outlet />
      <TanStackRouterDevtools />
    </>
  ),
});
Enter fullscreen mode Exit fullscreen mode

Here we have the link for another routes. The outlet will render the content of the route.
The tanstack devtools is a tool that will contain some infos for the routes.

Let's create the files for each route. Create about.tsx file inside the routes directory. Now will see that the content of the file will be automatically generate for you.

src/routes/about.tsx

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

export const Route = createFileRoute("/about")({
  component: About,
});

function About() {
  return <div className="p-2">Hello from About!</div>;
}
Enter fullscreen mode Exit fullscreen mode

Let's create the home file:

src/routes/index.tsx

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

export const Route = createFileRoute("/")({
  component: Index,
});

function Index() {
  return (
    <div className="p-2">
      <h3>Welcome Home!</h3>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now let's create the users routes, to do this create a folder called users, inside create the index.tsx.

src/routes/users/index.tsx

import { createFileRoute, Link } from "@tanstack/react-router";
import { User } from "../../types/User";
import { useQuery } from "@tanstack/react-query";

export const Route = createFileRoute("/users/")({
  component: RouteComponent,
});

const getUsers = (): Promise<User[]> =>
  fetch("https://jsonplaceholder.typicode.com/users").then((res) => res.json());

function RouteComponent() {
  const { data } = useQuery({
    queryKey: ["users"],
    queryFn: async () => getUsers(),
  });

  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      {data?.map((user: User) => (
        <Link to="/users/$id" params={{ id: user.id.toString() }} className="">
          {user.name}
        </Link>
      ))}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here we are fetching the data of users using the react query, and for each user let's create a link for the details route.

To get the URL params we need to create the following file using $. So to get the id of the user we create the file $id.tsx.

src/routes/users/$id.tsx

import {
  createFileRoute,
  useLoaderData,
  useParams,
} from "@tanstack/react-router";

export const Route = createFileRoute("/users/$id")({
  component: RouteComponent,
  loader: async ({ params }) => {
    const userId = params.id;
    const response = await fetch(
      `https://jsonplaceholder.typicode.com/users/${userId}`
    );

    if (!response.ok) throw new Error("Failed to fetch data");

    const user = await response.json();
    return { user };
  },
  pendingComponent: () => <div>Loading...</div>,
});

function RouteComponent() {
  const { id } = useParams({ from: "/users/$id" });
  const { user } = useLoaderData({ from: "/users/$id" });

  return (
    <div>
      {id} - {user.name}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here instead of using react query to make the requests, I'm using the loader to get the data before the route is rendered. The pendingComponent will render some content before the request finish, for example a loading screen.

TO get the id of URL params we can use useParams hooks and the useLoaderData to get the data of loader.

Final Result:

Tanstack router example

That's all folks

Thank you very much for reading this far and stay well always!

Contacts:

Linkedin: https://www.linkedin.com/in/kevin-uehara/
Instagram: https://www.instagram.com/uehara_kevin/
Twitter: https://x.com/ueharaDev
Github: https://github.com/kevinuehara
dev.to: https://dev.to/kevin-uehara
Youtube: https://www.youtube.com/@ueharakevin/

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Explore a trove of insights in this engaging article, celebrated within our welcoming DEV Community. Developers from every background are invited to join and enhance our shared wisdom.

A genuine "thank you" can truly uplift someone’s day. Feel free to express your gratitude in the comments below!

On DEV, our collective exchange of knowledge lightens the road ahead and strengthens our community bonds. Found something valuable here? A small thank you to the author can make a big difference.

Okay