ルーティングの設定

SPAでは1つのページを動的に書き換えるため、ページ内容が書き換わってもそのままではURLは変わりません。しかし、ブックマークやページ履歴を利用したい場合等、ページ内容に応じてURLを変更したい場面があります。ToDoアプリでも、ユーザー認証を作成したことで目的が異なるページ内容が複数できたため、URLでページ内容が切り替わるように実装します。

ページは次の4つに分類し、それぞれにパスを割り当てます。

  • / :トップページ
  • /signup :サインアップページ
  • /login :ログインページ
  • /board :ToDoページ

URLと同様に、ページの題名要素もそのままでは変わりません。本ハンズオンでは実装しませんが、変更が必要な場合にはuseEffect等を利用して実装する必要があります。

React Routerの導入

ルーティングを実現するために、React用のルーティングライブラリであるReact Routerを導入します。

React Routerを使用することで、URLごとに使用するコンポーネントを制御したり異なるURLへ移動したりといったことを、簡単に実装することができます。

React RouterとTypeScript用の型定義をインストールするため、frontendディレクトリで次のコマンドを実行します。

npm install --save react-router-dom@5 @types/react-router-dom@5

ルーティングの設定

URLごとに使用するコンポーネントが切り替わるように実装するため、Appコンポーネントを次のように実装します。

import React from 'react';
import './App.css';
import { NavigationHeader } from './components/NavigationHeader';
import { TodoBoard } from './components/TodoBoard';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { Signup } from './components/Signup';
import { Login } from './components/Login';
import { Welcome } from './components/Welcome';

function App() {
  return (
    <BrowserRouter>
      <NavigationHeader />
      <Switch>
        <Route exact path="/board">
          <TodoBoard />
        </Route>
        <Route exact path="/signup">
          <Signup />
        </Route>
        <Route exact path="/login">
          <Login />
        </Route>
        <Route exact path="/">
          <Welcome />
        </Route>
      </Switch>
    </BrowserRouter>
  );
}

export default App;

まず、React Routerを有効にするため、BrowserRouterコンポーネントを使用します。

次に、URLによるルーティングを行うため、SwitchコンポーネントとRouteコンポーネントを使用します。(参考:Basic Routing | React Router

Switchコンポーネントの中でURLルーティングが有効になり、Routeコンポーネントのpathプロパティに指定されたURLにマッチしたら、子要素のコンポーネントが実行されます。

URLとのマッチングは、デフォルトでは部分一致で判定されるため、ここでは、完全一致を使用するためにexactプロパティを指定します。

ページ遷移の実装

トップページからサインアップページへの遷移

トップページからサインアップページへ遷移するため、Welcomeコンポーネントを次のように実装します。

src/components/Welcome.tsx

import React from 'react';
import {Link} from 'react-router-dom';
import './Welcome.css';

export const Welcome: React.FC = () => {
  return (
    <div className="Welcome_content">
      <div>
        <h1 className="Welcome_title">Welcome</h1>
        <div className="Welcome_buttonGroup">
          <Link to="/signup">
            <button className="Welcome_button">登録する</button>
          </Link>
        </div>
      </div>
    </div>
  );
};

「登録する」ボタンがクリックされたら/signupURLへ遷移するように、Linkコンポーネントを使用します。toプロパティには、遷移先のURLを指定します。(参考:Basic Routing | React Router

サインアップ後のトップページへの遷移

サインアップしたらトップページへ遷移するため、Signupコンポーネントを次のように実装します。

src/components/Signup.tsx

import React from 'react';
import { useHistory } from 'react-router-dom';
import './Signup.css';

export const Signup: React.FC = () => {
  const history = useHistory();

  const signup: React.FormEventHandler<HTMLFormElement> = async (event) => {
    event.preventDefault();
    history.push('/');
  };

  return (
    <div className="Signup_content">
      <div className="Signup_box">
        <div className="Signup_title">
          <h1>ユーザー登録</h1>
        </div>
        <form className="Signup_form" onSubmit={signup}>
          <div className="Signup_item">
            <div className="Signup_label">名前</div>
            <input type="text" />
          </div>
          <div className="Signup_item">
            <div className="Signup_label">パスワード</div>
            <input type="password" />
          </div>
          <div className="Signup_buttonGroup">
            <button type="submit" className="Signup_button">登録する</button>
          </div>
        </form>
      </div>
    </div>
  );
};

ReactRouterが提供しているフックのuseHistoryを使うことで、コンポーネントの処理中にURL遷移を行うことができます。(参考:useHistory

ここでは、「登録する」ボタンをクリックしたら、トップページに遷移するようにします。最終的にはアカウントの登録処理が完了したら遷移するように実装しますが、ここではまず遷移のみ実装しておきます。

ナビゲーションメニューからの遷移

ヘッダの「ログイン」リンクからログインページへ遷移するのと、同じくヘッダの「ログアウト」からトップページへ遷移するため、NavigationHeaderコンポーネントを次のように実装します。

import React from 'react';
import './NavigationHeader.css';
import { Link } from 'react-router-dom';

export const NavigationHeader: React.FC = () => {

  const logout = async () => {
    window.location.href = '/';
  };

  return (
    <header className="PageHeader_header">
      <h1 className="PageHeader_title">Todoアプリ</h1>
      <nav>
        <ul className="PageHeader_nav">
          <li>
            <Link to="/login">ログイン</Link>
          </li>
          <li>テストユーザさん</li>
          <li>
            <button type="button" onClick={logout}>ログアウト</button>
          </li>
        </ul>
      </nav>
    </header>
  );
};

ここでは、ログアウト時にページを読み込み直してReactの状態を安全に破棄するよう、ReactRouterではなくwindows.location.hrefを使用します。

ログイン後のToDoページへの遷移

ログインしたらToDoページへ遷移するため、Loginコンポーネントを次のように実装します。

src/components/Login.tsx

import React  from 'react';
import { useHistory } from 'react-router-dom';
import './Login.css';

export const Login: React.FC = () => {
  const history = useHistory();

  const login: React.FormEventHandler<HTMLFormElement> = async (event) => {
    event.preventDefault();
    history.push('/board');
  };

  return (
    <div className="Login_content">
      <div className="Login_box">
        <div className="Login_title">
          <h1>ログイン</h1>
        </div>
        <form className="Login_form" onSubmit={login}>
          <div className="Login_item">
            <div className="Login_label">名前</div>
            <input type="text" />
          </div>
          <div className="Login_item">
            <div className="Login_label">パスワード</div>
            <input type="password" />
          </div>
          <div className="Login_buttonGruop">
            <button type="submit" className="Login_button">ログインする</button>
          </div>
        </form>
      </div>
    </div>
  );
};

動作確認

サインアップやログイン等の処理はまだ実装していませんが、ページを表示してページ遷移することができるようになりましたので、一度フロントエンドアプリを起動して、動作確認をしてみましょう。

フロントエンドアプリを起動していない場合は、frontendディレクトリで次のコマンドを実行します。

npm start

フロントエンドアプリが起動したら、ページを操作して動作を確認します。

results matching ""

    No results matching ""