web-dev-qa-db-ja.com

React Lazy + Suspenseでコンポーネントをプリロードする

現在、コードベースをコード分割するために、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ではロードされませんでした

enter image description here

ここで何が欠けていますか?

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;
9
ronnyrr

これは信じられないほど簡単に実行できます。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'));
1
James Friedman

これがどれほど役立つかわかりませんが、これは code sandbox が機能することです(デモはcomponentDidMountによってロードされます)。これは、構成にcreate-react-appを使用したコードのかなり簡略化されたバージョンです。おそらく、これを開始点として、徐々にアプリに近づけてモーフィングして、動的インポートが期待どおりに機能しなくなった原因を確認できます。

1
Ryan Cogswell