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>;
}
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();
}
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>;
}
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();
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>
);
}
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>
✅ CORRECT:
<Link to={'/pokemon/$id'} params={{ id: pokemon.id }}>
{pokemon.name}
</Link>
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:
Feel free to follow me to get notified when new articles are out ;)
Top comments (0)