React Loadableの紹介

こんにちは、Habr。 James Kyleの記事「React Loadableの紹介」の無料翻訳を紹介します。 その中で、Jamesはコード分離へのコンポーネント指向のアプローチとは何かについて語り、彼が開発したLoadableライブラリを紹介します-React.jsアプリケーションでこのアプローチを実装できるツールです。



画像

単一のアセンブリファイルおよび複数のファイルからのアセンブリ



翻訳者から:翻訳されていない音訳形式で一般的に使用される一部の動詞や用語(「プリローダー」や「レンダリング」など)を翻訳しないようにしました。



アプリケーションのコードベースの成長に伴い、1つのアセンブリファイルが最初のページの読み込み速度に悪影響を及ぼし始める時期があります。 コードを複数のファイルに分割し、それらを動的にダウンロードすると、この問題が解決します。



BrowserifyやWebpackのような最新のツールはこれをうまく機能させます。



同時に、どの原則コードフラグメントを1つのファイルに結合するか、およびアプリケーションが次のフラグメントの正常なロードについて学習し、このイベントを処理する方法を決定する必要があります。



コード分​​離へのルート指向およびコンポーネント指向のアプローチ



最近では、ほとんどすべての場所でルート指向のアプローチが使用されています。 つまり コードの断片は、各ファイルのコードがアプリケーションの特定のページ(ルート)の操作に必要であるという原則に基づいて、別々のファイルに割り当てられます。 そして、このアプローチの使用は非常に論理的です。なぜなら、リンクをクリックし、その後ページがロードされるのを待つことは、ユーザーにとって標準的で馴染みのあるアクションだからです。



しかし、完璧に制限はありません。このアプローチを改善してみませんか?



React.js上のアプリケーションの場合、ルートは単なるコンポーネントです。 これは、コンポーネント指向のアプローチを使用してコードを分離できることを意味します。



画像

ルート指向およびコンポーネント指向のアプローチで構築する



個別のファイルに分離するのが論理的であるコードを持つコンポーネントがたくさんあります。 モーダルウィンドウ、非アクティブなタブ、およびその他の多くのインターフェイス要素は、最初は非表示になっており、ユーザーが特定のアクションを実行しないと、ページにまったく表示されない場合があります。



では、なぜページに入るとすぐに、これらのコンポーネントのコード(および、おそらくこれらのコンポーネントを操作するためのサードパーティライブラリのコード)を読み込む必要があるのでしょうか?



同時に、コンポーネント指向のアプローチでは、コードをアプリケーションルートで分割することも非常に効果的です。これは、前述したように、ルートは単なるコンポーネントであるためです。 そのため、アプリケーションに最適な方法を実行してください。



そしてもちろん、コンポーネント指向のコード分離を実装するために多くの労力を費やす必要はありません。 コンポーネントを別のコードフラグメントに選択するには、アプリケーションの複数の行を変更するだけで十分であり、他の「マジック」は参加せずに「内部」で実行されます。



React Loadableの概要



私は小さなライブラリ-React Loadableを書きました。これにより、すべてを正確に思い通りに行うことができます。



2つのコンポーネントがあるとします。 AnotherComponent



コンポーネントをインポートし、 MyComponent



コンポーネントのrender



メソッドで使用します。



 import AnotherComponent from './another-component'; class MyComponent extends React.Component { render() { return <AnotherComponent/>; } }
      
      





現在、インポートは同期的に行われます。 非同期にする方法が必要です。



これは、 動的インポートを使用して実行できます。 AnotherComponent



非同期にAnotherComponent



ようにMyComponent



コードを変更します。



 class MyComponent extends React.Component { state = { AnotherComponent: null }; componentWillMount() { import('./another-component').then(AnotherComponent => { this.setState({ AnotherComponent }); }); } render() { let {AnotherComponent} = this.state; if (!AnotherComponent) { return <div>Loading...</div>; } else { return <AnotherComponent/>; }; } }
      
      





ただし、このような非同期ロードの実装では、コンポーネントコードの大幅な変更が必要です。 ただし、動的なインポートが失敗した場合についてはまだ説明していません。 しかし、サーバー側アプリケーションもレンダリングする必要がある場合はどうでしょうか?



高次のLoadable



コンポーネントを使用する(react.jsを使用する場合、おそらくこの用語とそのようなコンポーネントを使用する原則を知っているでしょう。そうでない場合は、 ドキュメントの対応するセクションを読むか、これが反応コンポーネントを受け入れる関数であることを考慮してください入力、およびそれに基づいて、拡張された動作を備えた新しいコンポーネントを返します-約。)私のライブラリから、これらすべての問題から抽象化することができます。



Loadable



は非常に簡単です。



最低限必要なのは、 loader



プロパティを持つオブジェクトをLoadable



Loadable



ことですLoadingComponent



は、コンポーネントと、読み込みプロセス中に表示されるコンポーネントであるLoadingComponent



動的インポートを実行する関数です。



 import Loadable from 'react-loadable'; function MyLoadingComponent() { return <div>Loading...</div>; } const LoadableAnotherComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent }); class MyComponent extends React.Component { render() { return <LoadableAnotherComponent/>; } }
      
      





しかし、コンポーネントのダウンロードが失敗するとどうなりますか?



エラーを何らかの方法で処理し、ユーザーに通知する必要があります。

エラーが発生した場合、コンポーネントプロパティ(prop)としてLoadingComponentに渡されます。



 function MyLoadingComponent({ error }) { if (error) { return <div>Error!</div>; } else { return <div>Loading...</div>; } }
      
      





2番目のバージョンのWebpackは、「すぐに使える」動的インポートで動作します-動的インポートを介して別のファイルに接続されたコードを選択し、実行時にロードします。 これは、アプリケーションに最適なコード分割スキームを簡単に実験して見つけることができることを意味します。



私のリポジトリからデモプロジェクトを実行することで、実際の例を見ることができます 。 また、Webpack 2が動的インポートでどのように機能するかについて詳しく知りたい場合 、公式ドキュメントの以下の セクションをご覧ください。



コンポーネントの「プリブートフリッカー」の防止



特定の条件下では、コンポーネントのロードは非常に迅速に(200ミリ秒未満で)発生する可能性があります。 これにより、プリローダーコンポーネントの画面に短期的な外観が表示され、ロードされたコンポーネントによって即座に置き換えられます。 ユーザーの目ではプリローダーを見る時間はありません。コンポーネントをロードする前に特定の「ちらつき」に気付くだけです。



この動作により、ユーザーは実際に発生する時間よりも長いロード時間を主観的に認識することが多くの研究で証明されています。 つまり この場合、プリローダーをまったく表示せずに、コンポーネントがロードされるのを待つことをお勧めします。



MyLoadingComponent



には、コンポーネントがロードを開始してから200ミリ秒が経過したときにtrue



に設定されたpastDelay



プロパティもあります(このソリューションが完全に機能していないことがわかります-コンポーネントのロードに400ミリ秒かかると、200ミリ秒待機した後、プリローダーが表示されます同じ200ミリ秒間画面に表示されます-翻訳者の考え)



 export default function MyLoadingComponent({ error, pastDelay }) { if (error) { return <div>Error!</div>; } else if (pastDelay) { return <div>Loading...</div>; } else { return null; } }
      
      





デフォルトでは200ミリ秒の値が使用されますが、対応するプロパティを指定することで変更できます。



 Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent, delay: 300 });
      
      





プリロード



さらに最適化するために、コンポーネントをプリロードして、ページにコンポーネントを表示する必要があるときには、そのコードがすでにロードされているようにすることもできます。 たとえば、ボタンをクリックした後、ページにコンポーネントを表示する必要があります。 この場合、ユーザーがこのボタンにカーソルを合わせるとすぐに、このコンポーネントのコードを含むファイルのダウンロードを開始できます。



Loadable



関数を呼び出して作成されたコンポーネントは、この目的のために静的なpreload



メソッドを提供します。



 let LoadableMyComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent, }); class MyComponent extends React.Component { state = { showComponent: false }; onClick = () => { this.setState({ showComponent: true }); }; onMouseOver = () => { LoadableMyComponent.preload(); }; render() { return ( <div> <button onClick={this.onClick} onMouseOver={this.onMouseOver}> Show loadable component </button> {this.state.showComponent && <LoadableMyComponent/>} </div> ) } }
      
      





サーバー側のレンダリング



私のライブラリは、サーバー側のレンダリングもサポートしています。



これを行うには、 Loadable



プロパティのLoadable



関数に引数として渡されるオブジェクトのコンポーネントへのフルパスを指定する必要があります。



 import path from 'path'; const LoadableAnotherComponent = Loadable({ loader: () => import('./another-component'), LoadingComponent: MyLoadingComponent, delay: 200, serverSideRequirePath: path.join(__dirname, './another-component') });
      
      





この場合、コンポーネントが存在するページがサーバー側でレンダリングされる場合、コンポーネントは同期的にロードされますが、クライアント側では非同期的にレンダリングされます。



同時に、サーバーコードでは、最初に読み込まれたhtmlファイルから接続される一般的なスクリプトファイルをアセンブルする問題を解決する必要があります。



上記のように、サーバー側でコンポーネントをレンダリングする場合、このコンポーネントを定義するモジュールへのフルパスは、 serverSideRequirePath



オブジェクトのserverSideRequirePath



プロパティで指定されます。 Loadable



ライブラリでは、 Loadable



関数がflushServerSideRequires



Loadable



関数を呼び出すと、現在のページのLoadableコンポーネントのすべてのモジュールへのパスから配列が返されます。 --json



フラグを使用して--json



を起動すると、アセンブリの完了時に、アセンブリに関する詳細情報output-webpack-stats.json



保存するoutput-webpack-stats.json



ファイルが作成されます。 このデータを使用して、アセンブリのどの部分が現在のページに必要かを計算し、生成されたページのhtmlファイル内のscript



タグを介してそれらを接続できます( コード例を参照)。



クライアントでこれをすべて解決できるようにWebpackを構成するという、まだ解決されていない最後のタスクが残っています。 ショーン、この記事の公開後のメッセージをお待ちします(ここでは、著者はWebpackプロジェクトの作成者でありメインメンテナであるショーンラーキンに対応します。今日、すでに翻訳を終えて、私はこのツイートに出会いました。サーバー側のレンダリングの実装はさらに簡素化されます-約



潜在的に、私は多くのツールとテクノロジーを想像できます。それらをライブラリと組み合わせて使用​​すると、アプリケーションがさらにクールになります。 たとえば、 React Fiber



を使用すると、コンポーネントコードを動的にロードできるだけでなく、「スマート」レンダリングも実装できます。つまり、 ロードされたコンポーネントのどの部分を最初にレンダリングし、どの部分を遅延させるか、つまり優先する より優先度の高い要素のレンダリングが完了した後にのみ。



結論として、私のライブラリをインストールして試してみてください。また、 リポジトリにgithubで 「スター」を付けるようにしてください。



 yarn add react-loadable # or npm install --save react-loadable
      
      






All Articles