react-router-dom ページごとにファイルを分割する
react-router-dom
でシングルアプリケーションを作成していると、ページ数が増えるにしたがって作成されるjs
ファイルのファイルサイズもどんどん増えていきます。
ページごとにファイルを分割し、そのページがアクセスされたタイミングでそのjs
ファイルを読み込むようにすれば最初のロード時間を短縮できます。
React
+react-router-dom
の構成なら簡単に遅延ローディングを実現できます。
React react-router-domの基本的な使い方で紹介したソースを修正します。
また、ページごとのコンポーネントは以下のフォルダ構成で配置されているものとします。
- pages
- Top
- index.tsx
- About
- index.tsx
- Contact
- index.tsx
- Top
遅延ローディング処理
以下の処理を追加します。
React
のlazy
を使用すると、ファイルが分割され、処理が呼び出されたタイミングで分割したファイルを読み込むようになります。
import { lazy } from 'react';
const LazyLoadedPage = (
pageName: string,
): React.LazyExoticComponent<React.ComponentType> => {
return lazy(() => import(`@/pages/${pageName}`));
};
ルーティング設定
ルーティング設定を修正します。
直接コンポーネントを参照するのではなく、さきほどで作成したLazyLoadedPage
を使用して、動的に読み込むようにします。
route.tsx
import { Route, Switch } from 'react-router-dom';
import { VFC } from 'react';
import Home from './Home';
import About from './About';
const routes: VFC = () => {
return (
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" exact component={About} />
<Route path="/" exact component={LazyLoadedPage('Home')} />
<Route path="/about" exact component={LazyLoadedPage('About')} />
</Switch>
);
};
export default routes({});
Suspenseの設定
上記の状態で実行すると、以下のエラーが発生します。
Error: A React component suspended while rendering, but no fallback UI was specified.
ページにアクセスしたタイミングで、ファイルが読み込まれますが、ファイルが読み込まれている最中はSuspended
という状態になります。
以下のように、Suspense
タグで囲い、Suspended
の状態のときはfallback
で指定した別のコンポーネントが表示されるようにして、エラーにならないようにします。
route.tsx
import { Route, Switch, Suspense } from 'react-router-dom';
import { VFC } from 'react';
const routes: VFC = () => {
return (
<Suspense fallback={<div>読込中</div>}>
<Switch>
<Route path="/" exact component={LazyLoadedPage('Home')} />
<Route path="/about" exact component={LazyLoadedPage('About')} />
</Switch>
</Suspense>
);
};
export default routes({});
実行
ビルドをするとXXX.chunk.js
のファイルが作成されることが確認できます。(XXX
はランダムな文字列)
実際にアクセスしてみると、about
ページに遷移するタイミングで分割されたファイルが読み込まれることが確認できます。