# The useMatches hook in Remix

If you use Remix, there's a hook that you can use called [`useMatches`](https://remix.run/docs/en/v1/api/remix#usematches), this hook is a way to access some internal data Remix has about your app, and it let's you a lot of things! It's so awesome, that you could re-implement some of the features Remix has using it!

The hook will return an array with this interface:

```ts
interface Match {
  pathname: string;
  params: Params<string>;
  data: RouteData;
  handle: any;
}
```

And that array will have one match for each route that matches the current path. This usually mean you'll have at least two matches, one for the `root.tsx` and another for your route, if your route has nested routes then it will have more matches.

What's so special about this? You can for example use the `match.data` key to access the data returned by the loaders of a route. Or use the `match.handle` to get access to the `handle` export of the route.

The documentation shows you how to use the `handle` export to pass elements from a child route to a parent route and render a breadcrumb. To me, the most useful property is the `data`.

With the `match.data` you can access to dynamic data, not static data as the breadcrumb example shows. Let's see an example:

```tsx
import { useMatches } from "remix";

export function useFlashMessages(): string[] {
  return useMatches()
    .map((match) => match.data)
    .filter((data) => Boolean(data.flash))
    .map((data) => data.flash);
}
```

With this hook, we could access the `flash` property returned by any loader to get any flash message the route wants to show, then in our `root.tsx` (or anywhere else actually) we could call our `useFlashMessages` hook to render them.

```tsx
function FlashMessages() {
  let flashMessages = useFlashMessages();

  return (
    <div>
      {flashMessages.map((message) => (
        <div>{message}</div>
      ))}
    </div>
  );
}
```

In my [Remix i18next package](https://github.com/sergiodxa/remix-i18next) I use this hook to get the translations a route need.

```ts
let namespaces = useMatches()
  .flatMap((match) => (match.data?.i18n ?? {}) as Record<string, Language>)
  .reduce((messages, routeMessages) => ({ ...messages, ...routeMessages }), {});
```

This way, any loader can return a `i18n` key with all the translations it loaded for that route and the user locale, in the root I can get them and pass them to i18next to use them.

You could even use it to access a route data based on their pathname. This way you don't need to use context to pass data from a parent route to a child route, and you will be able to get a child data from a parent route.

```ts
function useParentData(pathname: string): unknown {
  let matches = useMatches();
  let parentMatch = matches.find((match) => match.pathname === pathname);
  if (!parentMatch) return null;
  return parentMatch.data;
}
```