LoginSignup
4
3

More than 5 years have passed since last update.

react-router でログイン済みユーザー向けのページを PrivateRoute でやるのにハマったところ

Posted at

まえがき

v4 です。

困った!

ページで componentWillReceiveProps でやればよいはずの処理が走らず、なぜか毎回 componentWillMount が走っていた。つまり、component が update (re-render) するのではなく mount (re-mount) をしてた。なんでだろうな〜と思ったら、そのページはログイン済みの(authenticated な)ユーザーにのみ表示するページで、 PrivateRoute(後述)を使用していた。react-router の公式ドキュメントをちゃんと読んでごにょごにょしたら解決策がわかった。

公式のやりかた

公式ドキュメント はこんな風にやろうって言っている。

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      fakeAuth.isAuthenticated ? (
        <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: "/login",
            state: { from: props.location }
          }}
        />
      )
    }
  />
);

こんな感じで Route をいい感じに wrap して PrivateRoute として使う。こうすると、 isAuthenticated でないときには勝手にログインページへ redirect してくれる。使うときは Route を使うときと同じ要領で、 <PrivateRoute path="/mypage" component={Mypage} /> って感じにすればよい。

でも問題がある

僕らは Route にページコンポーネントを渡すとき、 component は使いたくない。なぜなら、

When you use component (instead of render or children, below) the router uses React.createElement to create a new React element from the given component. That means if you provide an inline function to the component prop, you would create a new component every render. This results in the existing component unmounting and the new component mounting instead of just updating the existing component. When using an inline function for inline rendering, use the render or the children prop (below).

(拙訳)
これを使うと、内部では毎回 React.createElementをやるので、レンダリング毎に新しい React element を生成しちゃいます。つまり、ページコンポーネントの update 処理をするのではなく、component の unmount & mount をしまくる、ってことになります。これが嫌だったら Route にページコンポーネントを渡すとき component じゃなくて render とか children とかを props で使おう。

src: https://reacttraining.com/react-router/web/api/Route/component

らしいから。

参考になる:https://qiita.com/park-jh/items/7486a0d1dcc5f32c69ec#render-props%E3%82%92%E4%BD%BF%E3%81%86

どうやるか

前述の PrivateRoute は、Routecomponent props を使う場合のやつなので、 render props を使うバージョンにする。

const PrivateRoute = ({ render, ...rest }) => (
  <Route
    {...rest}
    render={
      fakeAuth.isAuthenticated
        ? render
        : props => (
            <Redirect
              to={{
                pathname: "/login",
                state: { from: props.location }
              }}
            />
          )
    }
  />
);

使いかたは他の Route と同様、 <PrivateRoute path="mypage" render={props => <Mypage {...props} />} /> でオーケー。

あとがき

簡単ですね。

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