ReactRouterDom(Type Script)で遷移先にデータを渡す
前回、ReactHookFormを使ってフォームを作成しました。
結果表示ページに遷移し、入力内容を確認しようと思います。
使用している各バージョンは
react@18.2.0
react-hook-form@7.46.1
react-router-dom@6.15.0
typescript@4.9.5
React Router Domのインストール
ターミナル内でnpmを使ってインストールする
npm i react-router-dom
v5とv6
v5までは@typesもインストールしていましたが、v6から必要ないみたいです。
v5とv6の違いが気になる方はこちらを読み解きましょう。
RouterDomの使い方は後日のんびりと書きたいと思います。
Sampleアプリの作成
基本的には上記のアプリから起こしていきます。
interfaceの共通化
入力フォームから結果表示に渡すデータの型は共通である必要があるので、もともと入力フォーム用に作ってあったinterfaceを外に出します。
// Formに入力したデータ保存用のInterface
export interface InputData {
username: string;
gender: string;
month: string;
date: string;
message: string;
}
入力フォームの作成
App.tsxをページ振り分けのルーターだけの機能にするため、入力フォームのページを外に出します。
import { useNavigate } from 'react-router-dom'
import { InputData } from './InputData';
import { useForm } from 'react-hook-form';
import { ErrorMessage } from '@hookform/error-message';
export function InputPage() {
// Navigate関数
const navigate = useNavigate();
// 月リスト
const monthList: number[] = [];
for (let i = 1; i <= 12; i++) {
monthList.push(i);
}
// 日リスト
const dateList: number[] = [];
for (let i = 1; i <= 31; i++) {
dateList.push(i);
}
// 月の日にち最大値リスト
let datesOfMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
// useForm関数の設定
const {
register,
handleSubmit,
getValues,
formState: { errors },
} = useForm<InputData>({ mode: 'onChange', defaultValues: { gender: 'female' } });
// Submitイベント
const onSubmit = (data: InputData) => {
navigate('/result', {
state: data
});
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<h2>Input Form Test</h2>
<div>
<div>名前</div>
<div>
<input type="text"
{...register("username", {
required: "名前を入力してください",
})} />
</div>
<ErrorMessage
errors={errors}
name="username"
render={({ message }) => <div>{message}</div>}
/>
</div>
<div>
<div>性別</div>
<div>
<input type="radio" id="gender-male" value="male"
{...register("gender", {
required: true,
})} />
<label htmlFor="gender-male">男</label>
<input type="radio" id="gender-female" value="female"
{...register("gender", {
required: true,
})} />
<label htmlFor="gender-female">女</label>
</div>
</div>
<div>
<div>誕生日</div>
<div>
<select
{...register("month")}>
{monthList.map((item) => {
return (
<option key={item} value={item}>
{item}月
</option>
);
})}
</select>
<select
{...register("date", {
validate: {
message: value => {
const month = Number(getValues('month'));
const date = Number(value);
if (datesOfMonth[month - 1] < date) {
return "正しい日付を入力してください";
}
return;
}
}
})}>
{dateList.map((item) => {
return (
<option key={item} value={item}>
{item}日
</option>
);
})}
</select>
</div>
<ErrorMessage
errors={errors}
name="date"
render={({ message }) => <div>{message}</div>}
/>
</div>
<div>
<div>その他(100文字以内)</div>
<div>
<textarea
{...register("message", {
maxLength: { value: 100, message: "100文字以内で入力してください" }
})}
></textarea>
</div>
<ErrorMessage
errors={errors}
name="message"
render={({ message }) => <div>{message}</div>}
/>
</div>
<button type="submit">送信</button>
</form>
);
}
useNavigateでデータを渡す
前回のフォーム作成では、onSubmitイベントでダイアログ表示を行っていました。
今回はonSubmitイベント内でuseNavigateを使ってページの遷移を行います。
import { useNavigate } from 'react-router-dom'
import { InputData } from './InputData';
const navigate = useNavigate();
引き渡すデータ型を定義するため、InputDataをインポートします。
ReactRouterDomからuseNavigateをインポートし、useNavigateを宣言してnavigateで使用できるようにします。
// Submitイベント
const onSubmit = (data: InputData) => {
navigate('/result', {
state: data
});
}
navigateで画面遷移を行います。第一引数で遷移先を指定します。
第二引数の中の指定項目でstateに遷移先に渡したいデータを指定します。
今回はフォームの入力データを保存しているdata: InputDataを指定しました。
結果表示ページの作成
入力ページから送られてくるデータを受け取り、表示するためのページを作成します。
import { useLocation } from "react-router-dom";
import { InputData } from "./InputData";
export function ResultPage() {
// 前のページの情報を取得する
const location = useLocation();
const data = location.state as InputData;
const username = data.username;
const gender = data.gender;
const month = data.month;
const date = data.date;
const message = data.message;
return (
<div>
<p>name: {username}</p>
<p>gender: {gender}</p>
<p>Birthday: {month}/{date}</p>
<p>{message}</p>
</div>
);
}
useLocationでデータを受け取る
import { useLocation } from "react-router-dom";
import { InputData } from "./InputData";
遷移前のページからデータを受け取るため、useLocationもインポートします。
また、引き渡されるデータ型を知るため、こちらでもInputDataをインポートします。
// 前のページの情報を取得する
const location = useLocation();
const data = location.state as InputData;
最初にuseLocationを使用するために宣言します。
次に、遷移前のページから渡されてくるデータを読み取ります。この時、型をInputDataであると明示しておきます。
これにて、data変数内にInputData型のデータが格納されることになり、結果表示のページを作成できます。
Routerページを作成する
最後にInputPageとResultPageを分けるルーターをApp.tsx内に書き込んでいきます。
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { InputPage } from './InputPage';
import { ResultPage } from './ResultPage';
function App() {
return (
<BrowserRouter>
<Routes>
<Route index element={<InputPage />} />
<Route path={`result`} element={<ResultPage />} />
</Routes>
</BrowserRouter>
);
}
export default App;
URLに追記がなければインプットページ。resultが追加されれば結果ページに飛びます。
404ページは今回割愛しております。
結果
フォームに書いて送信すると結果ページに反映されています。
Discussion