# Bubble up data on Remix routes

React introduced a one-way data flow where a parent component has some data (state) and passes it to the children components as props.

In Remix, we can invert the data flow and let children's routes pass data to parent routes. We can do this by using the `useMatches` hook.

## Bubbling static data

Imagine this scenario, you're building a multi-step flow with some sidebar showing the progress, and each step is a nested route, so you have a folder structure like this:

```txt
└ app/
 └ routes/
 ├ multi-step-flow.tsx
 └ multi-step-flow/
 ├── step-1.tsx
 ├── step-2.tsx
 └── step-3.tsx
```

And you want to pass from `step-1`, `step-2`, and `step-3` the step name to `multi-step-flow` so it can show previous steps as completed.

You can pass static data by using the `handle` export from the children's routes:

```ts
export let handle = { step: "step-1" };
```

Now in the parent route, we can access this data using the `useMatches` hook:

```tsx
let matches = useMatches();
let match = matches.find((match) => "step" in match.handle);
let step = match.handle?.step as string;
```

With this, our parent route looks for every rendered route's `handle` export and finds the first one with the `step` property. Then it saves the step in a variable.

With these few lines of code, we could pass a static value from a child route to its parent route.

## Bubbling dynamic data

Another thing we could do is send dynamic data to a parent route. Let's say we're building a blogging platform, and the content can be in multiple languages, so we want to change the `<html lang>` attribute depending on the language of the current content. So we could have something like this:

```txt
└ app/
 ├ root.tsx
 └ routes/
 └ $content.tsx
```

On the `routes/$content.tsx` file, we might have a loader function that uses the parameter on the route to fetch the content from the database:

```tsx
export async function loader({ params }: LoaderArgs) {
  let slug = z.string().parse(params.content);
  let content = await Content.findBySlug(slug);
  return json(content);
}
```

And if `content` has a `lang` property, we know there will always be this `lang` on the loader data. We could use, again, `useMatches` to grab the data on the `root` route component.

```tsx
let matches = useMatches();
// here, we use match.data instead of match.handle
let match = matches.find((match) => "lang" in match.data);
let lang = match.data?.lang as string;

return <html lang={lang}> ... </html>;
```

And again, with a few lines of code, we could pass dynamic data from a child route to its parent route using the `loader` and `useMatches` hook.

## Bubbling functions

Let's say we need to know if the route required loading JS, so we could have some routes that don't load client-side JS while other routes do it.

A straightforward way to do this is by using the `handle` export to pass a boolean.

```ts
export let handle = { hydrate: true };
```

But if hydrating the route depends on the data we get from the loader, we can't use the `handle` export. We need the `loader`. But using a `loader` function would mean the route always needs to have a `loader`. To solve this, we can still use `handle` but simultaneously combine it with `loader`.

```tsx
export let handle = {
  hydrate(data: SerializeFrom<typeof loader>) {
    return data.hydrate;
  },
};
```

Now, in our `root` route component, we can use the `useMatches` hook to access this `hydrate` function and call it with the data from the loader.

```tsx
let matches = useMatches();
let shouldHydrate = matches.some((match) => {
  if (typeof match.handle?.hydrate === "function") {
    return match.handle.hydrate(match.data);
  }
  return match.handle?.hydrate ?? false;
});

return <html> ... {shouldHydrate ? <Scripts /> : null} ... </html>;
```

We check if `hydrate` is a function and call it by passing the `match.data` as an argument. If it's not a function, we use the value and default to `false` if it's not defined.

## Bubbling components

And since we can pass functions, we can also pass components because components are, in the end, just functions.

```tsx
export let handle = { Aside };

function Aside({ data }: { data: SerializeFrom<typeof loader> }) {
  return <aside> ... </aside>;
}
```

With this, we defined the component as a property of `handle`. This component could also receive the data from the `loader` as a `prop`.

Finally, in the parent route, we could render it.

```tsx
let matches = useMatches();
let match = matches.find(
  (match) => "Aside" in match.handle && typeof match.handle.Aside === "function"
);
let Aside = match.handle?.Aside as React.ComponentType<{ data: any }>;

return (
  <Layout>
    <Aside data={match.data} />
    <main>
      {" "}
      <Outlet />{" "}
    </main>
  </Layout>
);
```