見出し画像

【React×Typescript】React RouterのHooksを使ってみよう

おつかれさまです🌞
アイドルに課金するために働いているなりたです。

今回は React Router についての記事です。
私は React Router v5 を使っている期間が長く
v6 が出たから使ってみよう!となった際に
useHistory というHookが useNavigate という名前に変わっていたり
微妙にコードの書き方が変わっていたりして戸惑ったことがあります。

ということで、React Router の Hooks の一部を実際動かしつつ
たまにv5v6を比較しつつ
どんなことができるのかをまとめてみようと思います🏋️


useLocation

URLに関係するアレコレが取得できます。
v5 でも使えます。

  • location.hash 
    URLのハッシュの部分を取得します。

  • location.key 
    React Router が生成するユニークキーです。
    ページを遷移すると変わったりします。

  • location.pathname 
    URL(baseURL以降)を取得します。
    ハッシュとクエリは除外されています。

  • location.search 
    URLのクエリの部分を取得します。

  • location.state 
     Link や useNavigate の state で設定した値を取得します。

import { Link, useLocation } from "react-router-dom";

const LocationHook = () => {
  const location = useLocation();

  return (
    <table>
      <tbody>
        <tr>
          <td>{"hash : "}</td>
          <td>{location.hash}</td>
        </tr>
        <tr>
          <td>{"key : "}</td>
          <td>{location.key}</td>
        </tr>
        <tr>
          <td>{"pathname : "}</td>
          <td>{location.pathname}</td>
        </tr>
        <tr>
          <td>{"search : "}</td>
          <td>{location.search}</td>
        </tr>
        <tr>
          <td>
            <Link to={"/location?test=abc#sys21"} state={{ some: "value" }}>
              {"state : "}
            </Link>
          </td>
          <td>{JSON.stringify(location.state)}</td>
        </tr>
      </tbody>
    </table>
  );
};

export default LocationHook;

上記サンプルコンポーネント LocationHook{baseURL}/location で表示するようにして、{baseURL}/location にアクセスしてみます。

{baseURL}/location アクセス時の表示

サンプルコードではテーブル最下行の state : を押下すると /location?test=abc#sys21 へ遷移するように、
そして state{ some: "value" } を設定するようにしています。
ということで、このリンクを踏んでみます。

/location?test=abc#sys21 アクセス時の表示

様々な値が取得できました!
ちなみに同じリンクをもう一度押下すると key には別のハッシュ値が表示されました。

v5では…

<Link>で state を指定したい場合の書き方が少し違います。
先ほどと同じような遷移を行いたい場合には以下のようになります。

<Link
  to={{
    pathname: "/location?test=abc#sys21",
    state: { some: "value" },
  }}
>
  {"state : "}
</Link>

遷移先のURLも含めてパラメータとして渡すような感じです。
ちなみにクエリやハッシュも以下のように独立して書けます。

<Link
  to={{
    pathname: "/location",
    search: "?test=abc",
    hash: "#sys21",
    state: { some: "value" },
  }}
>
  {"state : "}
</Link>

useParams

こちらもv5でも使え、URLの文字列を取得することができます。
例えば以下のようなコンポーネントを作成し、App.tsx にてルーティング設定を行います。

Params.tsx

import { useParams } from "react-router-dom";

export let ParamsHookBlank = () => {
  return (
    <div>
      {"IDの指定なし"}
    </div>
  );
};

export const ParamsHook = () => {
  const { id } = useParams();
  return (
    <div>
      {`idは ${id} です!`}
    </div>
  );
};

App.tsx

import { BrowserRouter, Route, Routes } from "react-router-dom";
import { ParamsHook, ParamsHookBlank } from "./Params";

function App() {
  return (
    <div>
      <BrowserRouter>
        <Routes>
          <Route path={"/params"}>
            <Route index element={<ParamsHookBlank />} />
            <Route path={":id"} element={<ParamsHook />} />
          </Route>
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;
  • {baseURL}/params へアクセスすると
    ParamsHookBlank コンポーネントを表示

  • {baseURL}/params/{:id} へアクセスすると
    ParamsHook コンポーネントを表示

というルーティング設定をしました。
この状態でそれぞれのURLにアクセスすると…

{baseURL}/params アクセス時の表示
{baseURL}/params/sys21 アクセス時の表示

{baseURL}/params/{:id} にアクセスした際に {:id} 部分を取得して表示することができました!

v5では…

useParams にどういうパラメータがやって来るのかを教えてあげる必要がありました。

type ParamTypes = {
  id: string;
}

export const ParamsHook = () => {
  const { id } = useParams<ParamTypes>();

  return (
    <div>
      {`idは ${id} です!`}
    </div>
  );
};

useNavigate

v5 でいうところの useHistory に当たるものです。
ページの遷移に使用します。

ページの遷移といえば<Link>要素がありますが
こちらは処理の中でページ遷移を行いたい場合に使います。
そして使い方は基本的に useHistory と同じです。

以下のサンプルでは
ボタンを押下すると先ほど紹介した useLocation と同じように
クエリ等を指定したページ遷移を行うようなものになっています。
<Link>と同じように state も指定することができます。

import { useNavigate } from "react-router-dom";

const NavigateHook = () => {
  const navigate = useNavigate();
  const handleClick = () => {
    navigate("/location?from=navigate#abc", { state: { some: "navigate" } });
  };
  return (
    <div>
      <button onClick={handleClick}>ページ遷移</button>
    </div>
  );
};

export default NavigateHook;
[ページ遷移]ボタンを押下すると…
各種値を取得して表示できた

v5(useHistory)では…

history.push() に遷移先のURL等を渡します。

import { useHistory } from "react-router-dom";

const HistoryHook = () => {
  const history = useHistory();
  const handleClick = () => {
    history.push("/location?from=navigate#abc", {
      some: "navigate",
    });
  };
  return (
    <div>
      <button onClick={handleClick}>ページ遷移</button>
    </div>
  );
};

export default HistoryHook;

【おまけ】最終的なルーティング設定

今までのサンプルを表示するためのルーティング設定を最後に見てみました。
v6の方が要素のネストが少なくてなんだかスッキリしていますね😎

v6

import { BrowserRouter, Route, Routes } from "react-router-dom";
import LocationHook from "./Location";
import { ParamsHook, ParamsHookBlank } from "./Params";
import NavigateHook from "./Navigate";

function App() {
  return (
    <div>
      <BrowserRouter>
        <Routes>
          <Route path={"/location"} element={<LocationHook />} />
          <Route path={"/params"}>
            <Route index element={<ParamsHookBlank />} />
            <Route path={":id"} element={<ParamsHook />} />
          </Route>
          <Route path={"/navigate"} element={<NavigateHook />} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

v5

import { BrowserRouter, Switch, Route } from "react-router-dom";
import LocationHook from "./Location";
import HistoryHook from "./History";
import { ParamsHook, ParamsHookBlank } from "./Params";

function App() {
  return (
    <div>
      <BrowserRouter>
        <Switch>
          <Route path="/location">
            <LocationHook />
          </Route>
          <Route path="/params">
            <ParamsHookBlank />
          </Route>
          <Route path="/params/:id">
            <ParamsHook />
          </Route>
          <Route path="/history">
            <HistoryHook />
          </Route>
        </Switch>
      </BrowserRouter>
    </div>
  );
}

export default App;

最後に

改めてまとめてみるとv5/v6両方で使えるHookでも微妙にv6でアップデートされていることがあって新発見でした💡
今後もライブラリのアップデートに遭遇したときは注意深くドキュメントを読んでいきたいです!
(こういうドキュメントはほとんど英語なのでいつもすぐ挫折してしまいますが…😂)

参考文献

v6 ドキュメント

v5 ドキュメント