0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

かんたんにクライアントサイドルーティングを試してみる 後編

Posted at

はじめに

前回の記事の続きです。

ReactRouterの機能について引き続きまとめていきます。

今回はネストされたルート(Nested Routes)について扱います。

今までは付け焼き刃の知識で実装していたんだな、ということが前回の記事を通してわかったので、しっかりした知識を身につけられるようにします。

事前準備

こちらの環境構築が完了している前提です。
それに加えて、わかりやすいように見た目を整えておきたいので、styled-componentsをインストールします。

作成したプロジェクトをVS Codeで開いて、ターミナルから以下のコマンドを入力します。

npm install styled-components

image.png

インストールが完了次第、以降の工程に進みます。

そもそもネストされたルートとは

URLのパスの構造と、コンポーネントの階層構造を一致させることができる機能です。

ただ、文字だけだと直感的にわかりにくいので、実際に手を動かしながら確認します。

ネストされたルートを試す

どのような見た目になるか

先に完成形を確認します。

このページの構成として
メニュー
└設定
  └通知
のような階層構造になっています。

また、URLを確認すると
ルートパス/settings/notification
になっています。

これがネストされたルートです。
URLのパスの階層構造と、ページ(コンポーネント)の階層構造が一致しているので、作りとしてわかりやすいものになっています。

ReactRouterを使ってどのように実装するのかを見ていきます。

実際に作ってみる

特にポイントのないコンポーネントについては、冗長になるので以下から確認してください。

その他のコンポーネントを確認する
Notification.tsx
const Notification = () => {
  return (
    <>
      <h1>通知</h1>
    </>
  );
};

export default Notification;
Mail.tsx
const Mail = () => {
  return (
    <>
      <h1>メール</h1>
    </>
  );
};

export default Mail;

上記2つは設定ページのコンポーネントに紐づけます。

Customer.tsx
const Customer = () => {
  return (
    <>
      <h1>顧客情報</h1>
    </>
  );
};

export default Customer;

これはホームのコンポーネントに紐づけます。

子コンポーネントの描画を設定

ポイントは2つあります。
まず、親となるコンポーネントにおいて、子コンポーネントを描画するためのコンポーネントを設定することです。

設定ページのコンポーネントを見てみます。

Settings.tsx
import { Link, Outlet } from "react-router-dom";
import styled from "styled-components";
// スタイルの定義
const SettingsLayout = styled.div`
  display: flex;
  flex-flow: column;
`;
const TopNav = styled.nav`
  width: 70vw;
  border-bottom: 1px double gray;
`;
const TopNavUl = styled.ul`
  display: flex;
  list-style-type: none;
  padding: 0px;
`;
const TopNavLi = styled.li`
  margin-right: 10px;
`;

// 設定ページのコンポーネント
const Settings = () => {
  return (
    <SettingsLayout>
      <h1>設定情報</h1>
      <TopNav>
        <TopNavUl>
          <TopNavLi>
            <Link to="notification">通知</Link>
          </TopNavLi>
          <TopNavLi>
            <Link to="mail">メールアドレス</Link>
          </TopNavLi>
        </TopNavUl>
      </TopNav>
      {/* 子コンポーネントを描画する */}
      <Outlet />
    </SettingsLayout>
  );
};

export default Settings;

ごちゃごちゃいろいろ書いていますが、大半はスタイルのための定義なのでおいておきます。
大事なのはOutletコンポーネントです。

このコンポーネントは親子関係のある構造の親コンポーネントの方に定義します。
Outletコンポーネントを定義した部分に、子コンポーネントが描画されます。

なお、現時点では親子関係の定義はしていません。
これはまた別のところで実施します。

Linkコンポーネントは設定されたパスに飛ばすリンクを生成するだけなので、親子関係の定義とは関係ありません。

ホームのページのコンポーネントにも同様にOutletコンポーネントを定義します。
ポイントは同一なので、実際のコードは以下から確認してください。

ホームのコンポーネントを確認する
Home.tsx
import { Link, Outlet } from "react-router-dom";
import styled from "styled-components";
// スタイルの定義
const HomeLayout = styled.div`
  display: flex;
`;
const SideNav = styled.nav`
  width: 150px;
  height: 100vh;
  border-right: 1px solid gray;
  margin-right: 20px;
`;
const SideNavUl = styled.ul`
  list-style-type: none;
  padding: 0px;
`;
const SideNavLi = styled.li`
  margin-bottom: 10px;
`;

// ホームのページのコンポーネント
const Home = () => {
  return (
    <HomeLayout>
      <SideNav>
        <h1>メニュー</h1>
        <SideNavUl>
          <SideNavLi>
            <Link to="customer">顧客</Link>
          </SideNavLi>
          <SideNavLi>
            <Link to="settings">設定</Link>
          </SideNavLi>
          <SideNavLi>
            <Link to="/">ホームへ戻る</Link>
          </SideNavLi>
        </SideNavUl>
      </SideNav>
      {/* 子コンポーネントを描画する */}
      <Outlet />
    </HomeLayout>
  );
};

export default Home;

親子関係の設定

次に、main.tsxを以下のように書き換えます。

main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import {
  RouteObject,
  RouterProvider,
  createBrowserRouter,
} from "react-router-dom";
import Home from "./Home.tsx";
import Customer from "./Customer.tsx";
import Settings from "./Settings.tsx";
import Notification from "./Notification.tsx";
import Mail from "./Mail.tsx";
const routes: RouteObject[] = [
  {
    path: "/",
    element: <Home />,
    // Homeコンポーネントの子
    children: [
      {
        path: "customer",
        element: <Customer />,
      },
      {
        path: "settings",
        element: <Settings />,
        // Settingsコンポーネントの子
        children: [
          {
            path: "notification",
            element: <Notification />,
          },
          {
            path: "mail",
            element: <Mail />,
          },
        ],
      },
    ],
  },
];
const router = createBrowserRouter(routes);
ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>
);

基本的な作りは前回の記事と変わりません。

ルート情報のオブジェクトに新しくchildrenというプロパティを追加しています。
これが親子関係の設定になります。

customersettingsのパスは/のパスのchildrenに定義されています。
よって、/customer/settingsにアクセスされたとき、それぞれのコンポーネントを描画するという設定になります。

ここでのコンポーネントの描画位置はOutletコンポーネントを設定した場所です。

ネストを深くすることもできます。
settingsにはさらにchildrenを設定しています。
これにより、/settings/notification/settings/mailにアクセスされたとき、それぞれのコンポーネントを描画します。

改めて完成形を確認

ホームのページでは右側には何も表示されません。

「設定」のリンクを押下するとsettingsへ遷移するため、設定ページが表示されます。
しかし、それ以上は何も表示されません。

設定ページの「通知」をクリックすると、設定情報のページに、さらに通知ページが表示されます。

このように、childrenプロパティで親子関係を設定し、親コンポーネントにOutletコンポーネントを設定することで、指定のパスにアクセスされたとき子コンポーネントを描画することができます。

まとめ

ReactRouterの公式ページから重要と思われる2つの機能を取り上げて紹介しました。
なんとなくクライアントサイドルーティングできるものとして使っていましたが、その使い方や機能の豊富さに驚きました。

時間はかかりますが、公式サイトから基礎的な理解を深め、実践に持っていけるように日々意識したいと思いました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?