4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React】モーダルにURLを設定する

Last updated at Posted at 2022-08-20

はじめに

今回はReacr,React-Routerを使用し以下のような要件のモーダルを実装していきます。

  • モーダルにURLを付与したい。(モーダルを表示している状態を別ページ扱いとしたい)
  • 別のタブでURLを指定してアクセスした場合はモーダルではなく通常のページで表示したい。

※Reactなどについて詳しく解説はしません。

完成イメージ

t.gif

使用技術

nodeとnpmは以下バージョンを使用しています。

$ node -v
v16.16.0
$ npm -v
8.11.0

reactなどは以下バージョンを使用しています。

"react": "17.0.2",
"react-router-dom": "6.2.1",
"tailwindcss": "3.0.23" // スタイリングのために使用しています。

サンプルの実装

コンポーネント

まずは、モーダルを表示するためのボタンを配置するページを用意します。
ボタンにはReact Routerから提供されているLinkコンポーネントを使用していきます。
通常モーダルを実装する際はuseStateなどの状態管理を使用して実装しますが今回はルーティングでモーダルの表示非表示を管理していくので状態管理は必要ありません。
toには対象のモーダルに付与したいURLを指定します。
stateには{ backgroundLocation: location }を指定してください。こちらはコンテンツをモーダルとして表示するか通常のページとして表示するかの判定として使用される為重要な値となっています。
locationについては以下を参考にしてください。
参考: location

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

export const Home = () => {
  const location = useLocation();

  return (
    <div className="p-8">
      <button type="button">
        <Link to="/image" state={{ backgroundLocation: location }}>
          modal open
        </Link>
      </button>
    </div>
  );
};

続いて、モーダル表示用と通常のページで表示用のコンポーネントを作成します。今回は簡単に画像を表示するだけのものになっています。

Modal.jsx
import { useNavigate } from "react-router-dom";

export const Modal = () => {
  const navigate = useNavigate();
  const handleClose = () => {
    navigate("/");
  };

  return (
    <div className="fixed top-0 left-0 h-screen w-screen bg-black bg-opacity-10 pt-28">
      <div className="absolute top-28 left-1/2 inline-block max-h-full w-11/12 -translate-x-1/2 transform rounded-lg bg-white">
        <div className="relative p-6">
          <p className="mb-4">モーダル</p>
          <img
            src="https://images.unsplash.com/photo-1657266175529-1fd6a225d4a4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMTA3MjV8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk3MDg4NDk&ixlib=rb-1.2.1&q=80&w=1080"
            alt=""
            className="h-52 w-full rounded-lg object-cover"
          />
          <button
            type="button"
            onClick={handleClose}
            className=" absolute top-4 right-4 rounded-lg bg-primary text-center font-semibold text-white shadow-md hover:bg-primary-dark"
          >
            <svg className="cursor-pointer h-6 w-6 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}
            >
              <path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
            </svg>
          </button>
        </div>
      </div>
    </div>
  );
};
ImageView.jsx
export const ImageView = () => (
  <div className="p-8">
    <p className="mb-4">通常ページ</p>
    <img
      src="https://images.unsplash.com/photo-1657266175529-1fd6a225d4a4?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=MnwzMTA3MjV8MHwxfHJhbmRvbXx8fHx8fHx8fDE2NTk3MDg4NDk&ixlib=rb-1.2.1&q=80&w=1080"
      alt=""
      className="h-52 w-full rounded-lg object-cover"
    />
  </div>
);

ルーティング

最後にルーティングを設定します。
useLocation()locationを取得し、さらにlocationからLinkコンポーネントで渡したstate.backgroundLocationを取得します。
そして、Routerslocationというプロパティに取得したlocation,backgroundLocationを渡します。

AppRouter.jsx
import { Route, Routes, useLocation } from "react-router-dom";
import { Home } from "pages/Home";
import { Modal } from "pages/Modal";
import { ImageView } from "pages/ImageView";

export const AppRouter = () => {
  const location = useLocation();
  const backgroundLocation = location.state.backgroundLocation;

  return (
    <>
      <Routes location={backgroundLocation || location}>
        <Route path="/" element={<Home />} />
        <Route path="/image" element={<ImageView />} />
      </Routes>
    </>
  );
};

backgroundLocationがある場合のルーティングも記述します。
二つRoutersを記述することでモーダルの表示とモーダルの背面に表示される画面をルーティングすることができます。

AppRouter.jsx
~~~~
{backgroundLocation && (
  <Routes>
    <Route path="/image" element={<Modal />} />
  </Routes>
)}

動作確認

/homeにアクセスしボタンを押下するとURLが/imageに変わりモーダルが表示されます。モーダルと閉じると/homeへ変わりモーダルが非表示になります。
スクリーンショット 2022-08-20 17.00.23.png

次に、このモーダルのURLをコピーして別タブで開きます。すると、モーダルではなく通常のページで上記のモーダルと同様のコンテンツが表示されます。
スクリーンショット 2022-08-20 17.00.39.png

終わりに

以上で要件通りのモーダル実装完了です!
react-routerのv5とv6で記述方法が変わっているのでバージョンにはお気をつけてください!
少しでも参考になれば幸いです。

参考

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?