useMatches
Returns the current route matches on the page. This is most useful for creating abstractions in parent layouts to get access to their child route's data.
import { useMatches } from "react-router-dom";
function SomeComponent() {
const matches = useMatches();
// [match1, match2, ...]
}
A match
has the following shape:
{
// route id
id,
// the portion of the URL the route matched
pathname,
// the data from the loader
data,
// the parsed params from the URL
params,
// the <Route handle> with any app specific data
handle,
};
Pairing <Route handle>
with useMatches
gets very powerful since you can put whatever you want on a route handle
and have access to useMatches
anywhere.
useMatches
only works with Data Routers, since they know the full route tree up front and can provide all of the current matches. Additionally, useMatches
will not match down into any descendant route trees since the router isn't aware of the descendant routes.
The proverbial use case here is adding breadcrumbs to a parent layout that uses data from the child routes.
<Route element={<Root />}>
<Route
path="messages"
element={<Messages />}
loader={loadMessages}
handle={{
// you can put whatever you want on a route handle
// here we use "crumb" and return some elements,
// this is what we'll render in the breadcrumbs
// for this route
crumb: () => <Link to="/message">Messages</Link>,
}}
>
<Route
path="conversation/:id"
element={<Thread />}
loader={loadThread}
handle={{
// `crumb` is your own abstraction, we decided
// to make this one a function so we can pass
// the data from the loader to it so that our
// breadcrumb is made up of dynamic content
crumb: (data) => <span>{data.threadName}</span>,
}}
/>
</Route>
</Route>
Now we can create a Breadcrumbs
component that takes advantage of our home-grown crumb
abstraction with useMatches
and handle
.
function Breadcrumbs() {
let matches = useMatches();
let crumbs = matches
// first get rid of any matches that don't have handle and crumb
.filter((match) => Boolean(match.handle?.crumb))
// now map them into an array of elements, passing the loader
// data to each one
.map((match) => match.handle.crumb(match.data));
return (
<ol>
{crumbs.map((crumb, index) => (
<li key={index}>{crumb}</li>
))}
</ol>
);
}
Now you can render <Breadcrumbs/>
anywhere you want, probably in the root component.