前回の続きです。
引き続きルーティングを作成していきます。
ガイド
全体Index:タスク管理ツールをReact + ASP.Coreで作る - Index
概要
前回からルーティングを導入しましたが、若干行き当たりばったりで構築している感もあり、認証されてないページに飛ぶと詳細データは出ないもののそのまま読み込み状態で止まってしまったり、url設計せずに構築しているので名称の法則性が若干怪しかったりしているので、まずはurl設計から改めて実施していきましょう。
URL設計
URL設計は以下の様に設定してみました。
このシステムは基本的には認証されていない状態でやれることは特になくてよいのでルートにアクセスした場合は認証状態をチェックして認証されていればタスク管理画面、認証されていなければログイン画面に遷移する様にしました。
また、図には明記していませんが、ルート以外にも全体的に認証を要する画面にアクセスする場合は一度ユーザーの認証状態をチェックして、認証されていればその画面に遷移、認証されていなければログイン画面に遷移する様にしていこうと思います。
構築
上記のURL設計を元に実際に構築していきます。
まず、認証状態をチェックして遷移を制御するコンポーネントを作ります。
具体的にはユーザー情報を取得して、値が入っていれば認証済状態、入っていなければ認証未状態と判断し、認証済み状態であれば指定したURLに、認証未であればログイン画面に遷移させるという関数です。
import React from "react";
import { Navigate } from "react-router-dom";
import { UserInfo } from "../app/models/Account";
interface Props {
userInfo: UserInfo;
component: React.ReactNode;
redirect: string
}
export const RouteAuthChk = ({userInfo, component, redirect}: Props) => {
if (!userInfo.username) {
return <Navigate to={redirect} replace={false} />
}
return <>{component}</>;
}
App.tsxのルーティング用の設定を見直していきます。
具体的には各ルーティングの設定に上で作った認証状態チェックコンポーネントを挟む形の実装に変更しました。
また、元の実装のままだとユーザー情報をサーバーに問い合わせてチェックし終える前にその後の処理が走ってしまう仕様になっていたため、サーバー問い合わせが完了し、その時点でのユーザー情報が設定された後に移行の処理を動かすように設定を変更しました。
import { useEffect, useState } from 'react';
import { Route, Routes } from 'react-router-dom';
import './App.css';
import api from './app/api/api';
import { UserInfo } from './app/models/Account';
import Login from './components/Login';
import Register from './components/Register';
+ import { RouteAuthChk } from './components/RouteAuthChk';
import { TaskOperationMain } from './components/TaskOperationMain';
import { NavBar } from './NavBar';
function App() {
const [userInfo, setUserInfo] = useState<UserInfo>({username: '',email: '',token: ''});
+ const [isFirstLoginChecked, setIsFirstLoginChecked] = useState(false);
useEffect(() => {
const token = window.localStorage.getItem('tasket_jwt_token');
try{
api.Account.current().then(user => {
window.localStorage.setItem('tasket_jwt_token', user.token);
setUserInfo(user);
+ setIsFirstLoginChecked(true);
+ }).catch(x=>setIsFirstLoginChecked(true))
} catch (error) {
console.log(error);
}
}, []);
+ if(!isFirstLoginChecked) { return (<div>loading</div>) }
return (
<>
<NavBar userInfo={userInfo} setUserInfo={setUserInfo} />
<Routes>
+ <Route path = '/' element={ <RouteAuthChk userInfo={userInfo} component={<TaskOperationMain />} redirect="/login" /> } />
+ <Route path = '/task' element={ <RouteAuthChk userInfo={userInfo} component={<TaskOperationMain />} redirect="/login" /> } />
+ <Route path = '/task/:id' element={ <RouteAuthChk userInfo={userInfo} component={<TaskOperationMain />} redirect="/login" /> } />
+ <Route path = '/taskcreate' element={ <RouteAuthChk userInfo={userInfo} component={<TaskOperationMain />} redirect="/login" /> } />
+ <Route path = '/login' element={<Login setUserInfo={setUserInfo} />} />
+ <Route path = '/register' element={<Register />} />
</Routes>
</>
);
}
export default App;
参考
https://qiita.com/ayato_k/items/bed84dbdee79c68bd55a
https://zenn.dev/longbridge/articles/61b05d8bdb014d
https://zenn.dev/horisan/articles/2aeaf0bd3fb70f
https://reactrouter.com/en/v6.3.0/getting-started/overview
今回は以上です
続きは次回です