ReactでReact Routerを使いログインを実装する

#はじめに
今回はReactでReact Router を使ってログインの実装を行います。

React Routerを使えばサイト上にリンクを設置することができ、ページの行き来が可能になります。
また認証されてないユーザーに対してページを表示させないということもできます。

#インストール
今回はv6を使用します。
```npm install react-router-dom@6```

公式サイトURL
https://reactrouter.com/docs/en/v6/getting-started/installation

#サイト構築
まずは簡単なサイトをReact Routerを使って構築します。

```App.js
import * as React from "react";
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";

const AppBar = () => {
  return (
    <>
      <Link to="/">home</Link>
      <Link to="/login">login</Link>
    </>
  )
}
const Home = () => <p>Home</p>
const Login = () => <p>Login</p>

function App() {
  return (
    <BrowserRouter>
      <AppBar />
      <Routes>
         <Route path="/" element={<Home />} />
         <Route path="/login" element={<Login />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;
```

AppBarで返されるLinkコンポーネントを使ってページの移動を行います。
loginのリンクをクリックすれば/loginに飛ばされパラグラフのLoginが表示されます。
AppBarはRoutesの外側にあるのでどのページでも表示されるようになっています。

#仮認証実装
次に認証されていないユーザーに対してページを表示させないようにします。どのように認証するかはReactのContextを使って行います。

```AuthProvider.js
import React, { createContext, useContext, useState } from 'react';

const AuthContext = React.createContext();

const AuthProvider = ({children}) => {
  const [authenticated,setAuthenticated] = React.useState(false);

  function login () {
    setAuthenticated(true);
  }

  function logout () {
    setAuthenticated(false);
  }

  const auth = {
    authenticated,
    login,
    logout
  }

  return (
    <AuthContext.Provider value={auth}>
      {children}
    </AuthContext.Provider>
  );
}

const useAuth = () => {
  const context = useContext(AuthContext);

  return context;
};

export {AuthProvider,useAuth}
```
#ログインページ実装
次にAuthProviderとuseAuthを使って認証されてないユーザーに対してログインページに戻す機能を追加します。

```App.js
import * as React from "react";
import { BrowserRouter, Routes, Route, Link, Navigate } from "react-router-dom";

import {AuthProvider, useAuth} from './AuthProvider';

const AppBar = () => {
  return (
    <>
      <Link to="/">home</Link>
      <Link to="/login">login</Link>
      <Link to="/private">private</Link>
    </>
  );
}
const Home = () => <p>Home</p>
const Login = () => {
  const { authenticated, login, logout } = useAuth();
  return (
    <>
    {
      authenticated? <button onClick={logout}>LogOut</button> :
                     <button onClick={login}>LogIn</button>
    }
    </>
  );
}

function Authenticated({ children }) {
  const { authenticated } = useAuth();

  return authenticated === true
    ? children
    : <Navigate to="/login" replace />;
}

const Private = () => <p>Private</p>

function App() {
  return (
    <BrowserRouter>
      <AuthProvider>
        <AppBar />
        <Routes>
           <Route path="/" element={<Home />} />
           <Route path="/login" element={<Login />} />
           <Route path="/private"
                  element={<Authenticated>
                             <Private />
                           </Authenticated>} />
        </Routes>
      </AuthProvider>
    </BrowserRouter>
  );
}

export default App;
```
ログインページにloginまたはlogoutするボタンを追加しました。
これでログインしていないユーザーはプライベートのページを表示することはできません。

LogInのボタンを押すとauthenticatedがtrueになりPrivateのコンポーネントが表示されます。
ログインしてない状態で/privateのリンクを踏むと/loginに飛ばされます。

これでログインの実装ができました。

#参考
https://ui.dev/react-router-protected-routes-authentication/