Nested Routes and Parameterized Routes In Remix
Tags: remix, react, javascript, webdev
Published: 2022-02-15 21:48:38

##Overview
This video will walk through building a [Remix](https://remix.run/docs/en/v1) app that shows a list of teams and then a detailed view of each team. On the detailed page, we will have a list of players, which when clicked will show a detailed view of the player. The purpose of all of this is to show how to use Nested Routes In Remix

- The parent view/container will hold the navigation and the child components will be rendered in the provided Outlet
- We also show how to use the [OutletContext](https://reactrouterdotcom.fly.dev/docs/en/v6/api#useoutletcontext) that is provided for you by [react-router](https://reactrouterdotcom.fly.dev/docs/en/v6/)


This is what the final directory structure with files will look like

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fuv30qbb2duvjufc7riy.png)

## Video
{% youtube DdyNViscy94 %}

##Source Code 
{% stackblitz node-6sjyfk %}

##Code and Descriptions
The first thing we want to do is have the `index.tsx` redirect to our main page. I did not know of another way to do it using the router, so I just redirect in the loading of the index page

```jsx
// index.tsx
import { redirect } from "remix";

export const loader = async () => {
  return redirect("/teams");
};

export default function Index() {
  return (
    <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
      <h1>Welcome to Remix</h1>
     
    </div>
  );
}
```

Next, we create the root of the team pages we will be working on within the application. When the browser I directed to render `/teams` we will render `teams.tsx` And `/teams/index.tsx`

```jsx
// teams.tsx
import { Link, Outlet, useLocation } from "remix";

export default function Teams() {
  const teams = [
    {
      id: 1,
      name: "Team One",
      players: [
        {
          id: 1,
          name: "player one team one",
        },
        {
          id: 2,
          name: "player two team one",
        },
        {
          id: 3,
          name: "player three team one",
        },
      ],
    },
    { id: 2, name: "Team Two" },
    { id: 3, name: "Team Three" },
  ];

  // used for displaying the current application path
  const location = useLocation();

  return (
    <div
      style={{
        borderWidth: 1,
        borderColor: "grey",
        border: "solid",
        padding: 8,
      }}
    >
      <h1>TEAMS</h1>
      <Link to="/" style={{ margin: 8 }}>
        Home
      </Link>
      <Link to="create" style={{ margin: 8 }}>
        Add New Team
      </Link>
      <div style={{ margin: 8, marginTop: 32, background: "grey" }}>
        <!-- all of the pages in the /teams directory will be -->
        <!-- rendered here at this outlet, we can also pass   -->
        <!-- context information through the router           -->
        <Outlet context={[teams]} />
      </div>
      <pre>{location.pathname}</pre>
    </div>
  );
}
```

this is the code for `/teams/index.tsx`. here we are just rendering a list of teams which was passed down through the context that is defined in the router. We use the hook `useOutletContext` to get access to the context properties.

```jsx
// /teams/index.tsx
import { Link, useOutletContext } from "remix";

export default function TeamsIndex() {
  const [teams] = useOutletContext() as any;
  return (
    <div>
      <div
        style={{
          padding: 16,
          borderWidth: 1,
          borderColor: "grey",
          border: "solid",
        }}
      >
        <p>This is where the individual teams will appear</p>
        {teams?.map((t: any) => (
          <Link to={`/teams/${t.id}`}>
            <p>{t.name}</p>
          </Link>
        ))}
      </div>

    </div>
  );
}
```

As we loop through the teams in the array we got through the context, we want to be able to drill down, but keep the layout/framework around the `TeamsIndex` component. We do that by the way we structure the path for the next route.

```jsx
  <Link to={`/teams/${t.id}`}>
     <p>{t.name}</p>
  </Link>
```

The route `/teams/<id>` will be rendered in the same outlet that was defined in the `/teams/index.tsx`.

So now to see the detailed page, `$teamId.tsx`, with the team information and the list of players on the team, here is what the page would look like. The `$` in front of the name of the file is called parameterized route... meaning that when the route is resolved I will have access to a `teamId` param in the component, that value will be set when the route is set in the referring component

```jsx
// $teamId.tsx
import { Link, useOutletContext, useParams } from "remix";

export default function Team() {
  // get list of teams from context
  const [teams] = useOutletContext() as any;
  
  // the parameter is derived from the name of the file
  const { teamId } = useParams();

  // use parameter and the context to get specific team
  const team = teams[parseInt(teamId as string) - 1];
  
  return (
    <div style={{ padding: 16 }}>
      <p>{team?.name}</p>
      {team?.players?.map((p: any) => (
        <div style={{ paddingTop: 10 }}>
          <Link to={`/teams/${teamId}/player/${p.id}`}>
            <div>{p.name}</div>
          </Link>
        </div>
      ))}
      <div style={{ paddingTop: 16 }}>
        <Link to="/teams">
          <button type="button" className="button">
            Back
          </button>
        </Link>
      </div>
    </div>
  );
}
```

This pattern in the code above should start to look familiar at this point since it is very similar to how we displayed the list of teams in a nested component.

Finally our last route `/teams/$teamId/player/$playerId` will show us the specific player.

```jsx
import { Link, useOutletContext, useParams } from "remix";

export default function Player() {
  const [teams] = useOutletContext() as any;
  const { teamId, playerId } = useParams();

  const team = teams[parseInt(teamId as string) - 1];
  const player = team.players[parseInt(playerId as string) - 1];

  return (
    <div style={{ padding: 16 }}>
      <p>{team?.name}</p>
      <p>{player?.name}</p>

      <div style={{ paddingTop: 16 }}>
        <Link to={`/teams/${teamId}`}>
          <button type="button" className="button">
            Back
          </button>
        </Link>
      </div>
    </div>
  );
}
```

## Links
- Remix Docmentation - https://remix.run/docs/en/v1
- Source Code - https://stackblitz.com/edit/node-6sjyfk
- Remix Playlist  - https://buff.ly/3GuKVPS
- Outlet Context React Router - https://reactrouterdotcom.fly.dev/docs/en/v6/api#useoutletcontext