コード分割は、必要な場合にのみコードのチャンクをロードできる最新のWebアプリ開発でより多く使用されている手法です。 たとえば、ルートベースのコード分割を使用すると、ユーザーはアプリのさまざまなルートに移動でき、舞台裏では、各ルートのコードは初めてアクセスしたときにのみ読み込まれます。 コード分割を使用すると、アプリが初期化され、追加のコードがオンデマンドで読み込まれるときに、最小限のコードしか読み込むことができません。 これにより、初期バンドルサイズを小さくできるため、パフォーマンスが大幅に向上します。

React Loadable は、 @jamiebuilds によるライブラリであり、Reactでのコード分割の実装を容易にし、Reactのコンポーネントモデルを採用しています。 動的インポートを使用してその魔法を実現し、webpackは、バンドル時に動的インポートを個別のチャンクに自動的に分割します。

ReactLoadableの使い方を簡単に見ていきましょう。

インストール

npmまたはYarnを使用して、react-loadableパッケージをプロジェクトに追加するだけです。

$ npm install react-loadable

# or
$ yarn add react-loadable

使用法

Loadableがいかに単純であるかを説明するために、不自然な例を作成してみましょう。 まず、 SomeComponent

components / SomeComponent.js
import React from 'react';

function SomeComponent() {
  return <h1>Some Component! 💣🚀👨‍🎤🤘</h1>;
}

export default SomeComponent;

そして、それをAppコンポーネントで使用しましょう。

App.js
import React, { Component, Fragment } from 'react';
import SomeComponent from './components/SomeComponent';

class App extends Component {
  state = {
    showComponent: false
  };

  handleClick = () => {
    this.setState({
      showComponent: true
    });
  };

  render() {
    if (this.state.showComponent) {
      return <SomeComponent />;
    } else {
      return (
        <Fragment>
          <h1>Hello!</h1>
          <button onClick={this.handleClick}>Click me!</button>
        </Fragment>
      );
    }
  }
}

export default App;

ユーザーがボタンをクリックしたときにのみコンポーネントがビューにレンダリングされることに注意してください。 明らかに、このような単純なコンポーネントでは違いはありませんが、重要なアプリ内のより大きなコンポーネントでは、そのコンポーネントをコード分割することをお勧めします。

React Loadableを使用して、コード分割に少しリファクタリングしてみましょう。

App.js
import React, { Component, Fragment } from 'react';
import Loadable from 'react-loadable';

function Loading() {
  return <h3>Loading...</h3>;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

class App extends Component {
  state = {
    showComponent: false
  };

  handleClick = () => {
    this.setState({
      showComponent: true
    });
  };

  render() {
    if (this.state.showComponent) {
      return <SomeComponent />;
    } else {
      return (
        <Fragment>
          <h1>Hello!</h1>
          <button onClick={this.handleClick}>Click me!</button>
        </Fragment>
      );
    }
  }
}

export default App;

Loadable 高次コンポーネントは、loaderloadingの2つのキーを持つオブジェクトを受け取ります。

  • loader :Reactコンポーネントに解決されるpromiseを返す関数を期待しています。 import()を使用した動的インポートはpromiseを返すため、ロードするコンポーネントの場所を指定するだけです。
  • loading :コードのロード中にコンポーネントがレンダリングされることを期待します。

そして、それはそれと同じくらい簡単です! ブラウザのDevtoolsの[ネットワーク]タブを見ると、ボタンがクリックされたときにチャンクがロードされていることがわかります。

読み込み遅延

コンポーネントがすばやく読み込まれる場合、中間読み込みコンポーネントがあると、UIの視覚的な煩わしさの原因になる可能性があります。 幸い、Loadableは、 pastDelay 小道具の形で簡単な回避策を提供します。この小道具は、読み込みコンポーネントに渡され、特定の遅延が経過するとtrueと評価されます。

// ...

function Loading({ pastDelay }) {
  return pastDelay ? <h3>Loading...</h3> : null;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

// ...

デフォルトの遅延は200msですが、delay構成をLoadableHOCに渡すことで変更できます。 ここでは、たとえば、最大遅延を60msに変更します。

function Loading({ pastDelay }) {
  return pastDelay ? <h3>Loading...</h3> : null;
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading,
  delay: 60
});

エラー

別の小道具が読み込み中のコンポーネントerrorに渡されます。これにより、コンポーネントの読み込み中にエラーが発生した場合に、他の何かを簡単にレンダリングできます。

function Loading({ error }) {
  if (error) {
    return 'oh-noes!';
  } else {
    return <h3>Loading...</h3>;
  }
}

const SomeComponent = Loadable({
  loader: () => import('./components/SomeComponent'),
  loading: Loading
});

ルートベースのコード分割

多くの場合、アプリをコード分割する最も簡単な方法は、ルートレベルです。 React Router v4 を使用する場合のReactのルートは単なるコンポーネントであるため、React Loadableを使用して、さまざまなルートのコードをオンデマンドでロードするのも同じくらい簡単です。

ここでは、ReactLoadableを使用したルートベースのコード分割の簡単な例について説明します。 まず、プロジェクトでreact-router-domも使用できることを確認してください。

$ npm install react-router-dom

# or
$ yarn add react-router-dom

次の例では、 Dashboard コンポーネントを静的にインポートします。これは、ルートルートですぐに必要になるため、Loadableを使用してSettingsAddUserのみをロードします。 ]それぞれのルートがアクティブ化されたときのコンポーネント:

import React, { Component } from 'react';
import Loadable from 'react-loadable';
import { Link, Route, BrowserRouter as Router } from 'react-router-dom';

import Dashboard from './components/Dashboard';

function Loading({ error }) {
  if (error) {
    return 'Oh nooess!';
  } else {
    return <h3>Loading...</h3>;
  }
}

const Settings = Loadable({
  loader: () => import('./components/Settings'),
  loading: Loading
});

const AddUser = Loadable({
  loader: () => import('./components/AddUser'),
  loading: Loading
});

class App extends Component {
  render() {
    return (
      <Router>
        <div>
          <Link to="/">Dashboard</Link>
          <Link to="/settings">Settings</Link>
          <Link to="/add-user">Add User</Link>

          <Route exact path="/" component={Dashboard} />
          <Route path="/settings" component={Settings} />
          <Route path="/add-user" component={AddUser} />
        </div>
      </Router>
    );
  }
}

export default App;

🏇そしてこれで、あなたはコード分割でレースに出かける必要があります! プロジェクトのReadmeを参照して、APIの詳細なモードの詳細と、サーバー側のレンダリングなどの高度なトピックに関するドキュメントを確認してください。