React Routerでページ制御

React Routerを利用して、URLに応じて利用するページコンポーネントを切り替える方法を確認します。「URLパラメータを取得する方法」「非公開ページにする方法」など取り上げます。

環境

create-react-app でプロジェクト生成後、react-router-dom をインストールしてます。

npm install react-router-dom --save 
$ cat package.json | awk '/dependencies/,/}/'
  "dependencies": {
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-router-dom": "^5.1.2",
    "react-scripts": "3.2.0"
  },

動作確認用コード

フォルダ構成

今回は、以下フォルダ構成で動作確認を行います。

src/
├── index.js                                    // DOMにReact要素(App)を反映
├── App.js                                      // React Routerでページコンポーネントを切り替え
└── pages
    ├── home
    │   └── home.component.jsx                  // ログイン状態に関わらずアクセス可能
    ├── post-detail
    │   └── post-detail.component.jsx           // 未ログインであればアクセスさせない(sign-in-and-sign-upにリダイレクトさせる)
    ├── posts
    │   └── posts.component.jsx                 // 未ログインであればアクセスさせない(sign-in-and-sign-upにリダイレクトさせる)
    └── sign-in-and-sign-up
        └── sign-in-adn-sign-up.component.jsx   // ログイン中であればアクセスさせない(homeにリダイレクトさせる)

ページコンポーネント( 4つ )

pagesフォルダ 配下に4つのページコンポーネントを追加します。

home.component.jsx

import React from 'react'

const Home = props => (
  <div>
    <h2>Home</h2>
    <p>{`history: ${JSON.stringify(props.history, null, '\t')}`}</p>
    <p>{`location: ${JSON.stringify(props.location, null, '\t')}`}</p>
    <p>{`match: ${JSON.stringify(props.match, null, '\t')}`}</p>
  </div>
)

export default Home

post-detail.component.jsx

import React from 'react'

const PostDetail = props => (
  <div>
    <h2>PostDetail</h2>
    <p>{`history: ${JSON.stringify(props.history, null, '\t')}`}</p>
    <p>{`location: ${JSON.stringify(props.location, null, '\t')}`}</p>
    <p>{`match: ${JSON.stringify(props.match, null, '\t')}`}</p>
  </div>
)

export default PostDetail

posts.component.jsx

import React from 'react'

const Posts = props => (
  <div>
    <h2>Posts</h2>
    <p>{`history: ${JSON.stringify(props.history, null, '\t')}`}</p>
    <p>{`location: ${JSON.stringify(props.location, null, '\t')}`}</p>
    <p>{`match: ${JSON.stringify(props.match, null, '\t')}`}</p>
    <hr/>
    <button onClick={() => props.history.push(`${props.match.url}/1`)}>1</button>
    <button onClick={() => props.history.push(`${props.match.url}/2`)}>2</button>
  </div>
)

export default Posts

sign-in-adn-sign-up.component.jsx

import React from 'react'

const SignInAndSignUpPage = props => (
  <div>
    <h2>SignInAndSignUpPage</h2>
    <p>{`history: ${JSON.stringify(props.history, null, '\t')}`}</p>
    <p>{`location: ${JSON.stringify(props.location, null, '\t')}`}</p>
    <p>{`match: ${JSON.stringify(props.match, null, '\t')}`}</p>
  </div>
)

export default SignInAndSignUpPage

ページコンポーネントの切り替え

App.js

App.js にURLに応じてページコンポーネントを切り替える制御を記述します。

import React from 'react'
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  Redirect
} from 'react-router-dom'

import Home from './pages/home/home.component'
import Posts from './pages/posts/posts.component'
import PostDetail from './pages/post-detail/post-detail.component'
import SignInAndSignUpPage from './pages/sign-in-and-sign-up/sign-in-adn-sign-up.component'

const isAuthenticated = true

const App = () => {
  return (
    <div className="App">
      <p>{`isAuthenticated: ${isAuthenticated}`}</p>
      <Router>
        <div>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/signin">SingIn</Link></li>
            <li><Link to="/posts">Posts</Link></li>
            <li><Link to="/posts/1">Posts > 1</Link></li>
            <li><Link to="/posts/2">Posts > 2</Link></li>
          </ul>

          <hr/>

          <Switch>
            <Route exact path="/" component={Home}/>
            <Route exact path="/signin" render={props => isAuthenticated
              ? (<Redirect to="/"/>)
              : (<SignInAndSignUpPage {...props}/>)
            }/>
            <PrivateRoute exact path="/posts" component={Posts}/>
            <PrivateRoute exact path="/posts/:id" component={PostDetail}/>
          </Switch>
        </div>
      </Router>
    </div>
  )
}

const PrivateRoute = ({ component: Component, ...rest }) => {
  return (
    <Route {...rest} render={props => (isAuthenticated
        ? <Component {...props} />
        : <Redirect to="/signin"/>
    )}/>
  )
}

export default App

動作確認

上記コードの動作確認をします。

733-react-router_01_home.png

起動するとこのような画面が表示されます。

URLの完全一致|exact

App.js 内にて、 URL( / )Homeコンポーネント を紐づける記述にて、exact を指定しています。

<Route exact path="/" component={Home}/>

exact を指定することで、URLが完全一致したときだけ条件が満たされるようになります。

733-react-router_home_10_exact.png

試しに exactを取り除いてみると、URLが/signinなのに前方一致してしまい、Homeコンポーネントが表示されてしまいます。

ページ遷移

Linkコンポーネントを利用

App.js 内にて react-router-domLinkコンポーネント を利用してページ遷移を実装しています。

          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/signin">SingIn</Link></li>
            <li><Link to="/posts">Posts</Link></li>
            <li><Link to="/posts/1">Posts > 1</Link></li>
            <li><Link to="/posts/2">Posts > 2</Link></li>
          </ul>
733-react-router_home_20_link.gif

push関数を利用

posts.component.jsx 内にて historyオブジェクトがもつpush関数を利用してページ遷移を実装しています。

    <button onClick={() => props.history.push(`${props.match.url}/1`)}>1</button>
    <button onClick={() => props.history.push(`${props.match.url}/2`)}>2</button>
733-react-router_home_21_link.gif

propsに渡される情報

Routeコンポーネントでレンダリングされた、ページコンポーネントにはpropsが追加されています。
( history location match )

733-react-router_30_props.png

/posts/1でアクセスしたときのPostDetailコンポーネントのpropsです。

URLパラメータの取得

App.js 内にて /posts/:id のときに PostDetailコンポーネント を利用するように指定しています。

<PrivateRoute exact path="/posts/:id" component={PostDetail}/>

:id の値は PostDetailコンポーネントprops.match.params.id を通じて取得できます。

ログインページ
( ログイン済みであればリダイレクト )

App.js 内にて /signin のときにレンダリングするコンポーネントは isAuthenticated の状態に応じて変更するようにしています。

            <Route exact path="/signin" render={props => isAuthenticated
              ? (<Redirect to="/"/>)
              : (<SignInAndSignUpPage {...props}/>)
            }/>
733-react-router_40_signin.gif

isAuthenticated = trueの状態であるため、/signinにアクセスしても/にRedirectされています。

非公開ページ
( 未ログインであればリダイレクト )

App.js 内にて、未ログイン( isAuthenticated = false ) の場合、/posts /posts/:id にアクセスすると /signin にリダイレクトするようにしています。

            <PrivateRoute exact path="/posts" component={Posts}/>
            <PrivateRoute exact path="/posts/:id" component={PostDetail}/>
const PrivateRoute = ({ component: Component, ...rest }) => {
  return (
    <Route {...rest} render={props => (isAuthenticated
        ? <Component {...props} />
        : <Redirect to="/signin"/>
    )}/>
  )
}
733-react-router_50_private.gif

App.js にて、isAuthenticated = falseに変更して動作確認します。

/posts /posts/:id にアクセスしても /signin にリダイレクトされています。

参考

【エンジニア向け】仕事を見つける方法

転職する

転職エージェントを活用する

転職サイトの場合、自身でサイト上から企業を探す必要があります。 一方「レバテックキャリア」 などの転職エージェントの場合、エージェントが企業を紹介してくれます。エージェントが間に入ることにより、日程調整や、条件交渉などもサポートしてくれます。

転職ドラフトを活用する

転職ドラフト」は、 企業がITエンジニアをドラフトという形で指名するサービスです。年収が最初に提示されるなどのメリットがあります。 ただ、初回登録時にレジュメ作成が必要で、すでにエンジニア経験が豊富にあるエンジニア向けのサービスかと思います。 レジュメ作成が手間ですが、自身のキャリアを見直す機会になり、他の仕事探しにも役立つはずです。

エンジニア転職保証のあるスクールを活用する

ある程度、開発経験のあるかたであれば、独学で必要なスキルを身につけることができるはずです。ただ、別業種からエンジニアに転職したい場合など、1から独学で学ぶのはハードルが高いです。そういった方は、スクールの活用を検討しても良いと思います。 「TechAcademy」は、エンジニア転職保証コースを提供しています。給付金制度の対象講座として認定されているため、金銭面の負担も抑えることができます。

フリーランスとして活動する

レバテックフリーランス」「ITプロパートナーズ」「ギークスジョブ」は、フリーランスエージェントサービスです。 エージェントによって、支払いサイトなど細かい違いはありますが、まずは良い案件を見つけることが重要です。 登録自体は無料なので、複数エージェントに登録して、より多くの案件を紹介してもらうのがおすすめです。

logo
わくわくBank.
技術系の記事を中心に、役に立つと思ったこと、整理したい情報などを掲載しています。