タスク管理ツールをReact + ASP.Coreで作る023ReactRouterを導入する

[前回](https://qiita.com/mosuma/items/be9f6b343fd7af4d1f6c)の続きです



### ガイド
全体Index：[タスク管理ツールをReact + ASP.Coreで作る - Index](https://qiita.com/mosuma/items/88e40dc44e7bff1a54d8)


# 概要

これまでの構築でサイトの基本構成は出来てきました。
一方でアドレスバーを見ると分かりますが、どのページに遷移しても現状URLに変化がないことが分かります。
また、各操作を見ても、画面遷移などがほとんどできていない(認証状態に従って表示が切り替わるので画面遷移しているかのように見えているが、実際には画面遷移というより表示制御しているだけ)です。

各機能・ナビゲーションバーなどのサイト構成物の準備がある程度できたので、react-routerを導入して画面遷移を実装していこうと思います。
本記事では、まず導入としてReact Routerを導入して画面遷移の原理的な部分を作ってみます。

## 構築

### パッケージのインストール
以下のコマンドを入力して react-router-domをインストールします
```
> npm install react-router-dom
```

### index.tsxにルーターの大元を設定

index.tsxにBrowserRouterを設定します

```diff_tsx:index.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.min.css';
import 'react-datepicker/dist/react-datepicker.css';
+ import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
+       <BrowserRouter>
          <App />
+       </BrowserRouter>
  </React.StrictMode>
);

reportWebVitals();
```

### App.tsxにルーティング設定を適用

まずはユーザー認証された後のタスク関連を処理する部分にだけルーティングを適用してみます。
この段階だと一部の動作にだけルーティングが効くことになるので、動かすとかなり中途半端感がありますが、動作確認も兼ねてまず第一歩として今回はこの内容にしておこうと思います。

```diff_tsx: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 { TaskOperationMain } from './components/TaskOperationMain';
import { NavBar } from './NavBar';

function App() {

  
  const [userInfo, setUserInfo] = useState<UserInfo>({username: '',email: '',token: ''});
  
  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);
      });
      
    } catch (error) {
      console.log(error);
    }
  }, []);

  
  return (
    <>
      <NavBar userInfo={userInfo} />
+     {userInfo.username==='' && 
        <>
          <Login setUserInfo={setUserInfo}/>
          <Register /> 
        </>
      }      
+      <Routes>
+        <Route path="/" element={<TaskOperationMain />} />
+        <Route path = '/taskedit' element={<TaskOperationMain />} />
+        <Route path = '/taskedit/:id' element={<TaskOperationMain />} />
+        <Route path="/login" element={<Login setUserInfo={setUserInfo} />} />
+      </Routes>
     </>
  );
}


```





```diff_tsx:TaskOperationMain.tsx


+ import { useEffect, useState } from "react";
import { Button, Col, Row } from "react-bootstrap"
+ import { useParams } from "react-router-dom";
import { TaskEdit } from "./TaskEdit"
import { TaskList } from "./TaskList"


export const TaskOperationMain = () => {
    
+   const {id} = useParams<{id:string}>();
+    
+   useEffect(()=> {
+
+       if(id) {
+           setSelectedId_task(id);
+       } else {
+           setSelectedId_task("");
+       }

    }, [id])
    
    const [isModeAddnew, setIsModeAddnew] = useState(false);
    const [selectedId_task, setSelectedId_task] = useState("");

    return (
        <div>
            
            <Button variant="primary" onClick={()=>{setIsModeAddnew(true); setSelectedId_task("")}}>Add New Task</Button>

            <Row>
                <Col>
                    <TaskList setIsModeAddnew={setIsModeAddnew} selectedId_task={selectedId_task} setSelectedId_task={setSelectedId_task}/>
                </Col>
                <Col>
                    {
                        (isModeAddnew || selectedId_task !== "") &&
                            <TaskEdit isModeAddnew={isModeAddnew} id_task={selectedId_task} setSelectedId_task={setSelectedId_task} />
                    }
                </Col>
            </Row>
        </div>
    )
}


```





```diff_tsx:TaskList.tsx


import { useEffect, useState } from 'react';
import { Button, Table } from 'react-bootstrap';
+ import { useNavigate } from 'react-router-dom';
import api from '../app/api/api';
import { Task } from '../app/models/Task';



interface Props {
  selectedId_task: string;
  setIsModeAddnew: React.Dispatch<React.SetStateAction<boolean>>;
  setSelectedId_task: React.Dispatch<React.SetStateAction<string>>;
}


export const TaskList = ({setIsModeAddnew, selectedId_task, setSelectedId_task}: Props) => {
    
  
+   const navigate = useNavigate();
    
    const [loading, setLoading] = useState(true);
    const [tasks, setTasks] = useState<Task[]>();
  
    useEffect(() => {
        populateWeatherData();
    }, []);
  
    const populateWeatherData = async () => {
        const data = await api.Tasks.index();
        setTasks(data);
        setLoading(false);
    };
    
    if(loading) return <div>loading....</div>

    return (
        <div>
            <h1 id="tabelLabel">Task List</h1>
            <p>This component demonstrates fetching data from the server.</p>
            <Table >
              <thead>
                <tr>
                  <th>No.</th>
                  <th>Fin.</th>
                  <th>Title</th>
                  <th>Due Date</th>
                </tr>
              </thead>
              <tbody>
                {tasks && tasks.map((task, index) => (
                  <tr 
+                   key={task.id_task} onClick={()=>{setIsModeAddnew(false); setSelectedId_task(task.id_task);
+                     navigate(`/taskedit/${task.id_task}`);
+                   }}  
                    className={ selectedId_task === task.id_task ? "table-info" :  ""}                  
                  >
                    <td>{index+1}</td>
                    <td><input type="checkbox" defaultChecked={task.is_finish} disabled /></td>
                    <td>{task.title}</td>
                    <td>{task.end_date_scheduled && (new Date(task.end_date_scheduled).toDateString())}</td>
                  </tr>
                ))}
              </tbody>
            </Table>
        </div>
    )
}


```

今回は以上です。

続きは次回です