現在、コードベースをコード分割するために、React 16をSuspenseおよびLazyで使用しています。コンポーネントをプリロードしたいのですが。
以下の例では、2つのルートを取得しました。 Demo
がマウントされたらすぐにPrime
をプリロードする方法はありますか? componentDidMount
ページのPrime
に別の動的インポートを作成しようとしましたが、React.lazy
は、以下の動的インポートと同じファイルを取得していないようです。
import React, { lazy, Suspense } from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import GlobalStyle from 'styles';
import Loading from 'common/Loading';
const Prime = lazy(() => import(/* webpackChunkName: "Prime" */'modules/Prime'));
const Demo = lazy(() => import(/* webpackChunkName: "Demo" */'modules/Demo'));
const App = () => (
<main>
<GlobalStyle />
<Suspense fallback={<Loading>Loading...</Loading>}>
<Switch>
<Route path="/" component={Prime} exact />
<Route path="/demo" component={Demo} />
</Switch>
</Suspense>
</main>
);
export default withRouter(App);
したがって、以下のように、webpackChunkName
を使用する場合と使用しない場合、およびcomponentDidMount
に他のコンポーネントをインポートする方法など、さまざまな方法を試しました。 componentDidMount
にファイルをインポートする最初の2つの方法では、下の画像の下部にWebpackエラーが表示されていました。 3番目のみが続行されましたが、画像でファイル2.[hash].js
が作成され、ページが訪問された後にのみロードされ、componentDidMount
ではロードされませんでした
ここで何が欠けていますか?
modules/Demo.jsx
のコード:
import React from 'react';
import LogoIcon from 'vectors/logo.svg';
import PageLink from 'common/PageLink';
import Anchor from 'common/Anchor';
import CenteredSection from 'common/CenteredSection';
const Demo = () => (
<CenteredSection variant="green">
<LogoIcon />
<PageLink to="/" variant="green">Go to home page</PageLink>
</CenteredSection>
);
export default Demo;
これは信じられないほど簡単に実行できます。lazy()とSuspenseが内部で何をしているのかについて誤解があると思います。
React.lazy()の唯一の期待は、デフォルトのコンポーネントで解決するPromiseを返す関数を取ることです。
React.lazy(() => Promise<{default: MyComponent}>)
したがって、プリロードしたい場合は、事前にプロミスを実行するだけで済みます。
// So change this, which will NOT preload
import React from 'react';
const MyLazyComp = React.lazy(() => import('./path/to/component'));
/*********************************************/
// To this, which WILL preload
import React from 'react';
// kicks off immediately when the current file is imported
const componentPromise = import('./path/to/component');
// by the time this gets rendered, your component is probably already loaded
// Suspense still works exactly the same with this.
const MyLazyComp = React.lazy(() => componentPromise);
これは既知のシグネチャであるため、他のあらゆる状況で役立ちます。たとえば、動的に読み込まれるgoogle maps apiに依存する多数のコンポーネントがあり、google maps apiを読み込んでコンポーネントをインポートする関数を作成することができました。接線なので、この例の内部については詳しく説明しませんが、重要なのは、非同期の処理を実行して、{default:Component}のオブジェクトを持つPromiseを返す関数にしたことです。
import React from 'react';
const MyLazyComp = React.lazy(() => importMapsComponent('./path/to/comp'));
これがどれほど役立つかわかりませんが、これは code sandbox が機能することです(デモはcomponentDidMountによってロードされます)。これは、構成にcreate-react-appを使用したコードのかなり簡略化されたバージョンです。おそらく、これを開始点として、徐々にアプリに近づけてモーフィングして、動的インポートが期待どおりに機能しなくなった原因を確認できます。