1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

create-react-app で作った Reactプロジェクト でページ遷移する(react-router-dom)

Last updated at Posted at 2023-10-01

React でページ遷移の導入として react-router-dom(v6.16.0) を使ってやってみる
SPAとはいえページがあることで恩恵を受けることも結構あるのでやってみる
package.json に homepage 設定した時にちょっとはまった。。。
process.env.PUBLIC_URL を使うことで解決したのでそのあたりをメモしてます
ベースとして create-react-app から作ったプロジェクトから不要ファイル削除したやつを使ってます
やることとしては大雑把にこんな感じ

  • Reactプロジェクト作成 Win11
  • Reactプロジェクトから不要ファイル削除(./src直下削除)
  • Reactプロジェクトでページ遷移(react-router-dom v6.16.0使用)
    • react-router-dom インストール
    • ページのディレクトリ作成
    • ページ遷移の実装
    • ページ遷移の実装(コンポーネントにまとめる)
    • ページリンクのスタイル調整

あと最終的に出来上がるやつはここにおいてます
https://github.com/sueasen/my-app-react-router-dom

React プロジェクト作成 Win11

こちらのページ参考、Node.jsインストールからやってます

React プロジェクトから不要ファイル削除(./src直下削除)

こちらのページ参考、初期化して index.jsApp.js に簡単に分けてる感じです

Reactプロジェクトでページ遷移(react-router-dom v6.16.0使用)

react-router-dom インストール

以下のコマンドを実行するだけ

npm i react-router-dom

ページのディレクトリ作成

pages ディレクトリを src直下に作成する

ページ遷移の実装

ページ遷移の実装の流れとしては以下のステップを踏む

  • 遷移用ページのコンポーネント作成
  • BrowserRouter よりページ情報定義・表示
  • ページ遷移のリンク追加

遷移用ページのコンポーネント作成

pages直下に簡単に文字を表示するだけのページを3つ(Home, Page1, Page2)作成する
Page2props(引数) もらうようにしておく

Home.js
const Home = () => {
  return (
    <>
      <p>Home</p>
    </>
  );
};
export default Home;
Page1.js
const Page1 = () => {
  return (
    <>
      <p>Page1</p>
    </>
  );
};
export default Page1;
Page2.js
const Page2 = (props) => {
  return (
    <>
      <p>Page2 {props.text}</p>
    </>
  );
};
export default Page2;

BrowserRouter よりページ情報定義・表示

App.js に BrowserRouter 使ってページ情報を定義・表示するために以下をやる

  • BrowserRouter, Routes, Route を react-router-dom からインポート
  • ページ用コンポーネントをインポート
  • BrowserRouter の basename に process.env.PUBLIC_URL を設定
    • process.env.PUBLIC_URL を設定すると homepage 設定した時などパスが狂わなくなる
  • Route に各々の path, element(コンポーネント) を設定
App.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import Page1 from './pages/Page1';
import Page2 from './pages/Page2';

const App = () => {
  return (
    <>
      <h1>Hello World</h1>
      <p>App.jsx</p>
      {/* BrowserRouter, Routes, Route の定義、path に一致する element を表示 */}
      <BrowserRouter basename={process.env.PUBLIC_URL}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/page1" element={<Page1 />} />
          <Route path="/page2" element={<Page2 text="text sample" />} />
        </Routes>
      </BrowserRouter>
    </>
  );
};
export default App;

実行するとURLに応じてページが切り替わればO
image.png

ページ遷移のリンク追加

ページ遷移用のリンクを追加すればOK
設定するリンクには basename に設定した process.env.PUBLIC_URL を付けるとパスが狂わなくなる

App.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import Page1 from './pages/Page1';
import Page2 from './pages/Page2';

const App = () => {
  return (
    <>
      <h1>Hello World</h1>
      <p>App.jsx</p>
      {/* 以下リンクを追加 */}
      <ul>
        <li>
          <a href={`${process.env.PUBLIC_URL}/`}>Home</a>
        </li>
        <li>
          <a href={`${process.env.PUBLIC_URL}/page1`}>Page1</a>
        </li>
        <li>
          <a href={`${process.env.PUBLIC_URL}/page2`}>Page2</a>
        </li>
      </ul>
      {/* BrowserRouter, Routes, Route を定義 */}
      <BrowserRouter basename={process.env.PUBLIC_URL}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/page1" element={<Page1 />} />
          <Route path="/page2" element={<Page2 text="text sample" />} />
        </Routes>
      </BrowserRouter>
    </>
  );
};

export default App;

実行してリンクに応じてページが切り替わればOK
image.png

ページ遷移の実装(コンポーネントにまとめる)

ページ遷移の実装をコンポーネントにまとめてみる
ページ遷移に関する情報を変数定義してそれを渡して BrowserRouter, ページ遷移リンクを返すやつを作る
もっと良い方法ありそうだが定義したページ情報を渡せばできる形にしてみる

ページ遷移リンクのコンポーネント作成

ページ遷移リンク を返すコンポーネントを pages 直下に AppRouter.js として作る

AppRouter.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';

// pages は [{key:key1, path:path1, element:element1}, ...] を受け取る
export const appRouter = (pages) => {
  // BrowserRouter 返す処理
  const router = () => {
    return (
      <>
        <BrowserRouter basename={process.env.PUBLIC_URL}>
          <Routes>
            {pages.map((p) => (
              <Route key={p.key} path={p.path} element={p.element} />
            ))}
          </Routes>
        </BrowserRouter>
      </>
    );
  };
  // ページ遷移リンク 返す処理
  const links = () => (
    <ul>
      {pages.map((p) => (
        <li key={p.key}>
          <a href={`${process.env.PUBLIC_URL}${p.path}`}>{p.key}</a>
        </li>
      ))}
    </ul>
  );
  // BrowserRouter, ページ遷移リンク の定義を返す
  return {
    browserRouter: router(),
    navbarLink: links(),
  };
};

App.js から AppRouer.js を使って実装

インポートして pages を定義して AppRouer に設定する
後は browserRouter, navbarLink を使って書き換える

App.js
import { appRouter } from './pages/AppRouter';
import Home from './pages/Home';
import Page1 from './pages/Page1';
import Page2 from './pages/Page2';

// ページ情報を定義して appRouter に設定
const pages = [
  { key: 'Home', path: '/', element: <Home /> },
  { key: 'Page1', path: '/page1', element: <Page1 /> },
  { key: 'Page2', path: '/page2', element: <Page2 text="text sample" /> },
];
const router = appRouter(pages);

const App = () => {
  return (
    <>
      <h1>Hello World</h1>
      <p>App.jsx</p>
      {/* appRouter の navbarLink に書き換え*/}
      {router.navbarLink}
      {/* appRouter の browserRouter に書き換え*/}
      {router.browserRouter}
    </>
  );
};

export default App;

実行してページ遷移が出来ればOK!!

ページリンクのスタイル調整

メニューリンクなどにスタイルをあてる

  • App.css : 新規作成、スタイルを定義
  • App.js : インポート追加 App.css
  • AppRouter.js : タグやクラス属性を追加
App.css
body {
    margin: 0;
    font-family: "Futura", Helvetica, sans-serif;
}

/* Navbar & Navmenu color */
:root {
    --background-navbar: rgba(55, 55, 55, 0.98);
    --height-navbar: 52px;
}

.header {
    background: var(--background-navbar);
    position: fixed;
    width: 100%;
    height: var(--height-navbar);
    z-index: 3000;    
}

/* Nav items */
.menu {
    list-style: none;
    position: absolute;
    width: 100%;
    height: auto;
    top: 0;
    margin-top: var(--height-navbar);
    padding: 0 0 10px 0;
    clear: both;
    background: var(--background-navbar);
    transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
    transform: scale(1, 0);
    transform-origin: top;
}

/* Hamburger menu button */
.menu-btn:checked~.menu {
    transform: scale(1, 1);
    transform-origin: top;
    transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
}

/* Hamburger menbu text */
.menu a {
    text-decoration: none;
    font-weight: 500;
    letter-spacing: 2px;
    font-size: 16px;
    text-transform: capitalize;
    color: #ddd;
    opacity: 0;
    transition: 0.5s;
}

.menu li {
    border-top: 1px solid rgb(75, 75, 75);
    padding: 15px 0;
    margin: 0 54px;
    opacity: 0;
    transition: 0.5s;
}

.menu-btn:checked~.menu a,
.menu-btn:checked~.menu li {
    opacity: 1;
    transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.2s;
}

.menu-btn {
    display: none;
}

.menu-icon {
    display: inline-block;
    position: relative;
    cursor: pointer;
    padding: 24px 14px;
    -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

.navicon {
    background: #ddd;
    display: block;
    height: 3px;
    width: 26px;
    position: relative;
    transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
}

.navicon:before,
.navicon:after {
    content: "";
    display: block;
    height: 100%;
    width: 100%;
    position: absolute;
    background: #ddd;
    transition: 0.3192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
}

.navicon:before {
    top: 9px;
}

.navicon:after {
    bottom: 9px;
}

/* Hamburger Menu Animation Start */
.menu-btn:checked~.menu-icon .navicon:before {
    transform: rotate(-45deg);
}

.menu-btn:checked~.menu-icon .navicon:after {
    transform: rotate(45deg);
}

.menu-btn:checked~.menu-icon:not(.steps) .navicon:before {
    top: 0;
}

.menu-btn:checked~.menu-icon:not(.steps) .navicon:after {
    bottom: 0;
}

.menu-btn:checked~.menu-icon .navicon {
    background: rgba(0, 0, 0, 0);
    transition: 0.2192s cubic-bezier(0.04, 0.04, 0.12, 0.96) 0.1008s;
}

/* Hamburger Menu Animation End */

/* Navbar Container */
.navtext-container {
    width: 100%;
    height: var(--height-navbar);
    position: absolute;
    box-sizing: border-box;
    display: flex;
    justify-content: center;
    align-items: center;
}

/* Navbar Text */
.navtext {
    position: absolute;
    text-transform: uppercase;
    color: #ddd;
    letter-spacing: 4px;
    font-size: 20px;
}

main {
    padding-top: var(--height-navbar);
}
App.js
import { appRouter } from './pages/AppRouter';
import Home from './pages/Home';
import Page1 from './pages/Page1';
import Page2 from './pages/Page2';
// css 追加
import './App.css';

// ページ情報を定義して appRouter に設定
const pages = [
  { key: 'Home', path: '/', element: <Home /> },
  { key: 'Page1', path: '/page1', element: <Page1 /> },
  { key: 'Page2', path: '/page2', element: <Page2 text="text sample" /> },
];
const router = appRouter(pages);

const App = () => {
  return (
    <>
      {router.navbarLink}
      {/* 位置調整で main で括る */}
      <main>
        <h1>Hello World</h1>
        <p>App.jsx</p>
        {router.browserRouter}
      </main>
    </>
  );
};

export default App;
AppRouter.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';

export const appRouter = (pages) => {
  const router = () => {
    return (
      <>
        <BrowserRouter basename={process.env.PUBLIC_URL}>
          <Routes>
            {pages.map((p) => (
              <Route key={p.key} path={p.path} element={p.element} />
            ))}
          </Routes>
        </BrowserRouter>
      </>
    );
  };
  // タグ, クラスなど追加
  const links = () => (
    <header className="header">
      <div className="navtext-container">
        <div className="navtext">title</div>
      </div>
      <input type="checkbox" className="menu-btn" id="menu-btn" />
      <label htmlFor="menu-btn" className="menu-icon">
        <span className="navicon"></span>
      </label>
      <ul className="menu">
        {pages.map((p) => (
          <li key={p.key}>
            <a href={`${process.env.PUBLIC_URL}${p.path}`}>{p.key}</a>
          </li>
        ))}
      </ul>
    </header>
  );
  return {
    browserRouter: router(),
    navbarLink: links(),
  };
};

こんな感じで表示されればOK

image.png

1
3
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
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?