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.tsximport { 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.tsximport { 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ページに遷移するタイミングで分割されたファイルが読み込まれることが確認できます。