DEV Community

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

Posted on

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/

Top comments (0)