react-router v4 で onEnter ライクなことを実装する

1. Overview

react-routerにはあった onEnter というなにかしらの <Route /> に入ったときのフックポイントが用意されていました. しかしながら, v4 からはルーターの機能に特化したものとなり, onEnter などのフックポイントが廃止されました. しかしながら, onEnter ライクな処理をすることは可能なのでその実装方法をメモしておきます.

2. Implement routing by react-router v4

react-router v4 によるルーティングはおおよそ以下のような実装となります.

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

import Home from './components/Home';
import PageA from './components/PageA';
import PageB from './components/PageB';
import PageC from './components/PageC';

export default () => {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={Home} />
        <Route exact path="/a" component={PageA} />
        <Route exact path="/b" component={PageB} />
        <Route exact path="/c" component={PageC} />
      </Switch>
    </Router>
  );
};

3. onEnter

onEnter ライクな処理となる関数を実装します.

const render = (Component) => ({ history, match }) => {
  // ページローディングなどを表示する: 例 YouTube のページ上部に表示されるプログレスバーなど

  return <Component history={history} match={match} />;
};

ちょっと見づらいかもしれませんが, 関数が関数を返す, いわゆるクロージャ (高階関数) となっています.
history は, ネイティブの history オブジェクトではなく react-router が定義する history オブジェクトで, match は パスからパラメータを取得するためのオブジェクトです.

そして, ルーティングを以下のように実装します.

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

import Home from './components/app';
import PageA from './components/PageA';
import PageB from './components/PageB';
import PageC from './components/PageC';

const render = (Component) => ({ history, match }) => {
  // ページローディングなどを表示する: 例 YouTube のページ上部に表示されるプログレスバーなど

  return <Component history={history} match={match} />;
};

export default () => {
  return (
    <Router>
      <Switch>
        <Route exact path="/" render={render(Home)} />
        <Route exact path="/a" render={render(PageA)} />
        <Route exact path="/b" render={render(PageB)} />
        <Route exact path="/c" render={render(PageC)} />
      </Switch>
    </Router>
  );
};

注目すべきは, component props ではなく, render props になっていることです (ちなみに, component props と render props は共存できません).

これで onEnter ライクな処理が可能になります.