DEV Community

Cover image for TanStack Router: Path Parameters & Loader
Leonardo Montini for This is Learning

Posted on • Originally published at leonardomontini.dev

TanStack Router: Path Parameters & Loader

Welcome to the second article of a series where we will explore TanStack Router, the new typesafe routing library (and state manager, in some cases) for React.

In the first article we saw how to set up a new project with TanStack Router and how to create a couple of routes. In this article we'll see how to handle path parameters and how to use a loader to fetch data before rendering a route.

Path Parameters

Here's a demo of what you're going to learn in this article. For written instructions, keep reading below.

On your favourite social network, your account url will be somewhere around https://www.example.com/user/yourusername. The yourusername part is a path parameter, and it's a way to tell the application that you'd like to see the page for that specific user.

Let's expand the previous example using pokemons as the domain. We want to create a page for each pokemin, obviously using path parameters.

If you didn't follow the previous article it's not a problem, you can start from the code on the 01-routes-and-setup branch.

Adding a new route

Let's create a new file in src/routes/pokemon/$id.ts. You already see the path has a $id in it, which will be replaced in the URLs with our pokemon id.

Reading the path parameter

Now, how can we read the parameter? When we create our route we're also creating a Route object which we can use to call some hooks, and there's one exactly called useParams.

Your initial page to check that everything is working might be something like this:

export const Route = createFileRoute('/pokemon/$id')({
  component: Pokemon,
});

function Pokemon() {
  const { id } = Route.useParams();
  return <div>Pokemon {id}</div>;
}
Enter fullscreen mode Exit fullscreen mode

If you now navigate to http://localhost:5173/pokemon/1 you should see "Pokemon 1" on the screen. This already opens up to a lot of possibilities!

Loader

To make things more interesting, let's say we want to fetch the pokemon data from an API before rendering the page. We can use a loader for that.

Fetching the data

Here's an example to have an API, this isn't about TanStack router but only for the sake of the example. You can have on a file src/api/pokemon.ts:

type PokemonDetail = {
  name: string;
  id: number;
  height: number;
  weight: number;
  sprites: {
    front_default: string;
  };
};

export async function getPokemon(id: string): Promise<PokemonDetail> {
  const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${id}`);
  return await response.json();
}
Enter fullscreen mode Exit fullscreen mode

This gives us a function getPokemon that we can use to fetch the data for a specific pokemon.

Using the loader

One of the parameters of the createFileRoute function is the loader. This is a function that will be called before rendering the route, and it can be used to fetch data. You can update your Route object to include the loader:

import { createFileRoute } from '@tanstack/react-router';
import { getPokemon } from '../../api/pokemon';

export const Route = createFileRoute('/pokemon/$id')({
  component: Pokemon,
  loader: async ({ params }) => await getPokemon(params.id),
});

function Pokemon() {
  const { id } = Route.useParams();
  return <div>Pokemon {id}</div>;
}
Enter fullscreen mode Exit fullscreen mode

If you now refresh your page, you can already see in the network tab that the data is being fetched from the API and using it in the component is as easy as ready the path parameter since Route also exposes a useLoaderData hook.

const pokemon = Route.useLoaderData();
Enter fullscreen mode Exit fullscreen mode

You can now use the pokemon object to render the pokemon data on the screen, here's an example:

function Pokemon() {
  const { id } = Route.useParams();
  const pokemon = Route.useLoaderData();
  console.log(pokemon);
  return (
    <div>
      <h2>
        ({id}) {pokemon.name}
      </h2>
      <img src={pokemon.sprites.front_default} alt={pokemon.name} />
      <dl>
        <dt>Height</dt>
        <dd>{pokemon.height}</dd>
        <dt>Weight</dt>
        <dd>{pokemon.weight}</dd>
      </dl>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Navigating to a route with parameters

If you notice, when you try to navigate to a route with parameters, you cannot set an url like /pokemon/1 or /pokemon/${pokemonId} directly. TanStack Router will force you to pass the route definition as /pokemon/$id and then specify the parameter in the params object, for example:

❌ WRONG:

<Link to={`/pokemon/${pokemon.id}`}>{pokemon.name}</Link>
Enter fullscreen mode Exit fullscreen mode

✅ CORRECT:

<Link to={'/pokemon/$id'} params={{ id: pokemon.id }}>
  {pokemon.name}
</Link>
Enter fullscreen mode Exit fullscreen mode

Is it an additional step? Probably yes, but this makes sure you're passing the correct parameters and you have autocompletion and typesafety while doing so.

Conclusion

In this article we saw how to handle path parameters and how to use a loader to fetch data before rendering a route. This is a very powerful feature that can be used to create dynamic pages and fetch data from an API.

However, sometimes you have many parameters, even structured! You can't have a strict link with each parameter sequentially, right? That's why in the next chapter we're gonna see one of the greatest features of TanStack Router: search parameters (aka query params).

This library allows you to basically handle your application state in the URL as search params, with the huge advantage that you can let your users bookmark an URL or send it to someone else, passing the state of your application.

Some examples? A search page with filters, a form with a lot of fields or a dashboard with many configurations.

As always, the code for this chapter is on the 02-path-parameters branch and stay tuned for the next article!


Watch the full playlist on YouTube: TanStack Router


Thanks for reading this article, I hope you found it interesting!

I recently launched a GitHub Community! We create Open Source projects with the goal of learning Web Development together!

Join us: https://github.com/DevLeonardoCommunity

Do you like my content? You might consider subscribing to my YouTube channel! It means a lot to me ❤️
You can find it here:
YouTube

Feel free to follow me to get notified when new articles are out ;)

Top comments (0)