useMatches
Returns the current route matches on the page. This is useful for creating layout abstractions with your current routes.
function SomeComponent() {
const matches = useMatches();
// ...
}
matches
has the following shape:
[
{ id, pathname, data, params, handle }, // root route
{ id, pathname, data, params, handle }, // layout route
{ id, pathname, data, params, handle }, // child route
// etc.
];
Remix knows all of your route matches and data at the top of the React element tree. That's how we can:
<link>
tags to assets at the top of the document even though ...<script>
bundles for each route at the top of the document ...Pairing route handle
with useMatches
, you can build your own, similar conventions to Remix's built-in <Meta>
, <Links>
, and <Scripts>
components.
Let's consider building some breadcrumbs. If a route wants to participate in these breadcrumbs at the top of the root layout, it normally can't because it renders down low in the tree.
You can put whatever you want on a route handle
. Here we'll use breadcrumb
. It's not a Remix thing, it's whatever you want. Here it's added to a parent route:
Add the breadcrumb handle to the parent route
// routes/parent.tsx
export const handle = {
breadcrumb: () => <Link to="/parent">Some Route</Link>,
};
We can do the same for a child route
// routes/parent/child.tsx
export const handle = {
breadcrumb: () => (
<Link to="/parent/child">Child Route</Link>
),
};
Now we can put it all together in our root route with useMatches
.
import {
Links,
Scripts,
useLoaderData,
useMatches,
} from "@remix-run/react";
export default function Root() {
const matches = useMatches();
return (
<html lang="en">
<head>
<Links />
</head>
<body>
<header>
<ol>
{matches
// skip routes that don't have a breadcrumb
.filter(
(match) =>
match.handle && match.handle.breadcrumb
)
// render breadcrumbs!
.map((match, index) => (
<li key={index}>
{match.handle.breadcrumb(match)}
</li>
))}
</ol>
</header>
<Outlet />
</body>
</html>
);
}
Notice that we're passing the match
to breadcrumbs. We didn't use it, but we could have used match.data
to use our route's data in the breadcrumb.
Another common use case is enabling JavaScript for some routes and not others.
Once again, useMatches
with handle
is a great way for routes to participate in rendering abstractions at the top of element tree, above where the route is actually rendered.
For an example of how to share loader data via useMatches
, check out the sharing loader data example in the remix repo.