Reactを使用した非同期データの読み込み、遅延読み込み、コード分割の処理方法
著者は、 Creative Commons を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
JavaScript Web開発者として、非同期コードを使用すると、コードの一部を実行しながら、他の部分がデータを待機または解決することができます。 これは、アプリの重要な部分がレンダリングされる前に、重要性の低い部分を待つ必要がないことを意味します。 非同期コードを使用すると、新しい情報を要求して表示することでアプリケーションを更新することもでき、長い関数や要求がバックグラウンドで処理されている場合でもユーザーにスムーズなエクスペリエンスを提供します。
React 開発では、非同期プログラミングには固有の問題があります。 たとえば、React 機能コンポーネントを使用する場合、非同期関数は無限のループを作成する可能性があります。 コンポーネントがロードされると、非同期関数を開始できます。非同期関数が解決されると、再レンダリングがトリガーされ、コンポーネントが非同期関数を呼び出すことができます。 このチュートリアルでは、useEffect と呼ばれる特別なフックを使用してこれを回避する方法を説明します。このフックは、特定のデータが変更された場合にのみ関数を実行します。 これにより、各レンダリングサイクルではなく、意図的に非同期コードを実行できるようになります。
非同期コードは、新しいデータの要求だけに限定されません。 Reactには、遅延読み込みコンポーネント、またはユーザーが必要な場合にのみそれらを読み込むためのシステムが組み込まれています。 Create ReactAppのデフォルトのwebpack構成と組み合わせると、コードを分割して、大きなアプリケーションを必要に応じてロードできる小さな部分に縮小できます。 ReactにはSuspense
と呼ばれる特別なコンポーネントがあり、ブラウザーが新しいコンポーネントをロードしている間、プレースホルダーを表示します。 Reactの将来のバージョンでは、Suspense
を使用して、レンダリングをブロックせずにネストされたコンポーネントにデータをロードできるようになります。
このチュートリアルでは、河川に関する情報を表示し、setTimeout
を使用してWebAPIへのリクエストをシミュレートするアプリを作成することにより、Reactで非同期データを処理します。 このチュートリアルを終了すると、useEffect
フックを使用して非同期データをロードできるようになります。 また、データ解決の前にコンポーネントがアンマウントされた場合でも、エラーを発生させることなくページを安全に更新できます。 最後に、コード分割を使用して、大きなアプリケーションを小さな部分に分割します。
前提条件
- Node.jsを実行する開発環境が必要になります。 このチュートリアルは、Node.jsバージョン10.20.1およびnpmバージョン6.14.4でテストされました。 これをmacOSまたはUbuntu18.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはのPPAを使用したインストール]セクションの手順に従います。 Ubuntu18.04にNode.jsをインストールする方法。
- Create React App でセットアップされたReact開発環境で、不要なボイラープレートが削除されています。 これを設定するには、ステップ1 —Reactクラスコンポーネントの状態を管理する方法のチュートリアルの空のプロジェクトを作成します。 このチュートリアルでは、プロジェクト名として
async-tutorial
を使用します。 useState
やuseReducer
フックなどのReactイベントとフックを使用します。 イベントについては、 React チュートリアルでDOMおよびウィンドウイベントを処理する方法、およびReactコンポーネントのフックで状態を管理する方法でフックを学ぶことができます。- また、JavaScriptとHTMLの基本的な知識も必要です。これは、HTMLシリーズでWebサイトを構築する方法およびJavaScriptでコーディングする方法にあります。 CSSの基本的な知識も役立ちます。これは、 Mozilla DeveloperNetworkで見つけることができます。
ステップ1—useEffect
を使用した非同期データのロード
このステップでは、useEffect
フックを使用して、非同期データをサンプルアプリケーションにロードします。 フックを使用して、不要なデータフェッチを防ぎ、データの読み込み中にプレースホルダーを追加し、データが解決されたときにコンポーネントを更新します。 この手順を完了すると、useEffect
を使用してデータをロードし、解決時にuseState
フックを使用してデータを設定できるようになります。
このトピックを探索するために、世界で最も長い川に関する情報を表示するアプリケーションを作成します。 外部データソースへのリクエストをシミュレートする非同期関数を使用してデータをロードします。
まず、RiverInformation
というコンポーネントを作成します。 ディレクトリを作成します。
mkdir src/components/RiverInformation
テキストエディタでRiverInformation.js
を開きます。
nano src/components/RiverInformation/RiverInformation.js
次に、プレースホルダーコンテンツを追加します。
async-tutorial / src / components / RiverInformation / RiverInformation.js
import React from 'react'; export default function RiverInformation() { return( <div> <h2>River Information</h2> </div> ) }
ファイルを保存して閉じます。 次に、新しいコンポーネントをインポートしてルートコンポーネントにレンダリングする必要があります。 App.js
を開きます:
nano src/components/App/App.js
強調表示されたコードを追加して、コンポーネントをインポートしてレンダリングします。
async-tutorial / src / components / App / App.js
import React from 'react'; import './App.css'; import RiverInformation from '../RiverInformation/RiverInformation'; function App() { return ( <div className="wrapper"> <h1>World's Longest Rivers</h1> <RiverInformation /> </div> ); } export default App;
ファイルを保存して閉じます。
最後に、アプリを読みやすくするために、スタイルを追加します。 App.css
を開きます:
nano src/components/App/App.css
CSSを次のように置き換えて、wrapper
クラスにパディングを追加します。
async-tutorial / src / components / App / App.css
.wrapper { padding: 20px }
ファイルを保存して閉じます。 これを行うと、ブラウザが更新され、基本コンポーネントがレンダリングされます。
このチュートリアルでは、データを返すための汎用サービスを作成します。 サービスとは、特定のタスクを実行するために再利用できるコードを指します。 コンポーネントは、サービスがその情報を取得する方法を知る必要はありません。 知っておく必要があるのは、サービスがPromiseを返すことだけです。 この場合、データ要求はsetTimeout
でシミュレートされ、データを提供する前に指定された時間待機します。
src/
ディレクトリの下にservices
という名前の新しいディレクトリを作成します。
mkdir src/services
このディレクトリには、非同期機能が保持されます。 rivers.js
というファイルを開きます。
nano src/services/rivers.js
ファイル内で、promiseを返すgetRiverInformation
という関数をエクスポートします。 promise内に、1500
ミリ秒後にpromiseを解決するsetTimeout
関数を追加します。 これにより、データが解決されるのを待っている間にコンポーネントがどのようにレンダリングされるかを確認する時間ができます。
async-tutorial / src / services / rivers.js
export function getRiverInformation() { return new Promise((resolve) => { setTimeout(() => { resolve({ continent: 'Africa', length: '6,650 km', outflow: 'Mediterranean' }) }, 1500) }) }
このスニペットでは、河川情報をハードコーディングしていますが、この関数は、API呼び出しなど、使用する可能性のある非同期関数と同様です。 重要な部分は、コードがpromiseを返すことです。
ファイルを保存して閉じます。
データを返すサービスができたので、それをコンポーネントに追加する必要があります。 これにより、問題が発生する場合があります。 コンポーネント内で非同期関数を呼び出し、useState
フックを使用してデータを変数に設定するとします。 コードは次のようになります。
import React, { useState } from 'react'; import { getRiverInformation } from '../../services/rivers'; export default function RiverInformation() { const [riverInformation, setRiverInformation] = useState({}); getRiverInformation() .then(d => { setRiverInformation(d) }) return( ... ) }
データを設定すると、フックを変更するとコンポーネントが再レンダリングされます。 コンポーネントが再レンダリングされると、getRiverInformation
関数が再度実行され、コンポーネントが解決されると状態が設定され、別の再レンダリングがトリガーされます。 ループは永遠に続きます。
この問題を解決するために、ReactにはuseEffect
と呼ばれる特別なフックがあり、特定のデータが変更されたときにのみ実行されます。
useEffect フックは、最初の引数として function を受け入れ、2番目の引数としてトリガーのarrayを受け入れます。 この関数は、レイアウトとペイントの後の最初のレンダリングで実行されます。 その後、トリガーの1つが変更された場合にのみ実行されます。 空の配列を指定すると、1回だけ実行されます。 トリガーの配列を含めない場合、レンダリングのたびに実行されます。
RiverInformation.js
を開きます:
nano src/components/RiverInformation/RiverInformation.js
useState
フックを使用して、riverInformation
という変数とsetRiverInformation
という関数を作成します。 非同期機能が解決したときにriverInformation
を設定して、コンポーネントを更新します。 次に、getRiverInformation
関数をuseEffect
でラップします。 必ず2番目の引数として空の配列を渡してください。 約束が解決したら、riverInformation
をsetRiverInformation
関数で更新します。
async-tutorial / src / components / RiverInformation / RiverInformation.js
import React, { useEffect, useState } from 'react'; import { getRiverInformation } from '../../services/rivers'; export default function RiverInformation() { const [riverInformation, setRiverInformation] = useState({}); useEffect(() => { getRiverInformation() .then(data => setRiverInformation(data) ); }, []) return( <div> <h2>River Information</h2> <ul> <li>Continent: {riverInformation.continent}</li> <li>Length: {riverInformation.length}</li> <li>Outflow: {riverInformation.outflow}</li> </ul> </div> ) }
非同期関数が解決したら、順序付けされていないリストを新しい情報で更新します。
ファイルを保存して閉じます。 これを行うと、ブラウザが更新され、関数が解決された後にデータが表示されます。
データがロードされる前にコンポーネントがレンダリングされることに注意してください。 非同期コードの利点は、最初のレンダリングがブロックされないことです。 この場合、データなしでリストを表示するコンポーネントがありますが、スピナーまたはスケーラブルベクターグラフィック(SVG)プレースホルダーをレンダリングすることもできます。
ユーザー情報や変更されないリソースのリストを取得している場合など、データを1回だけロードする必要がある場合があります。 しかし、多くの場合、非同期関数にはいくつかの引数が必要になります。 そのような場合、データが変更されるたびにuseEffect
フックの使用をトリガーする必要があります。
これをシミュレートするには、サービスにデータを追加します。 rivers.js
を開きます:
nano src/services/rivers.js
次に、さらにいくつかの河川のデータを含むオブジェクトを追加します。 name
引数に基づいてデータを選択します。
async-tutorial / src / services / rivers.js
const rivers = { nile: { continent: 'Africa', length: '6,650 km', outflow: 'Mediterranean' }, amazon: { continent: 'South America', length: '6,575 km', outflow: 'Atlantic Ocean' }, yangtze: { continent: 'Asia', length: '6,300 km', outflow: 'East China Sea' }, mississippi: { continent: 'North America', length: '6,275 km', outflow: 'Gulf of Mexico' } } export function getRiverInformation(name) { return new Promise((resolve) => { setTimeout(() => { resolve( rivers[name] ) }, 1500) }) }
ファイルを保存して閉じます。 次に、App.js
を開いて、さらにオプションを追加できるようにします。
nano src/components/App/App.js
App.js
内に、 stateful 変数を作成し、useState
フックで選択した川を保持するように機能します。 次に、onClick
ハンドラーを使用して各河川にボタンを追加し、選択した河川を更新します。 name
と呼ばれるpropを使用して、river
をRiverInformation
に渡します。
async-tutorial / src / components / App / App.js
import React, { useState } from 'react'; import './App.css'; import RiverInformation from '../RiverInformation/RiverInformation'; function App() { const [river, setRiver] = useState('nile'); return ( <div className="wrapper"> <h1>World's Longest Rivers</h1> <button onClick={() => setRiver('nile')}>Nile</button> <button onClick={() => setRiver('amazon')}>Amazon</button> <button onClick={() => setRiver('yangtze')}>Yangtze</button> <button onClick={() => setRiver('mississippi')}>Mississippi</button> <RiverInformation name={river} /> </div> ); } export default App;
ファイルを保存して閉じます。 次に、RiverInformation.js
を開きます。
nano src/components/RiverInformation/RiverInformation.js
name
を小道具として引き込み、getRiverInformation
関数に渡します。 必ずname
をuseEffect
のアレイに追加してください。そうしないと、再実行されません。
async-tutorial / src / components / RiverInformation / RiverInformation.js
import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { getRiverInformation } from '../../services/rivers'; export default function RiverInformation({ name }) { const [riverInformation, setRiverInformation] = useState({}); useEffect(() => { getRiverInformation(name) .then(data => setRiverInformation(data) ); }, [name]) return( <div> <h2>River Information</h2> <ul> <li>Continent: {riverInformation.continent}</li> <li>Length: {riverInformation.length}</li> <li>Outflow: {riverInformation.outflow}</li> </ul> </div> ) } RiverInformation.propTypes = { name: PropTypes.string.isRequired }
このコードでは、PropTypes
を使用した弱い型付けシステムも追加しました。これにより、小道具が文字列であることを確認できます。
ファイルを保存します。 これを行うと、ブラウザが更新され、さまざまな川を選択できます。 クリックしてからデータがレンダリングされるまでの遅延に注意してください。
useEffect
アレイからname
小道具を省略した場合、ブラウザコンソールでビルドエラーが発生します。 これは次のようになります。
ErrorCompiled with warnings. ./src/components/RiverInformation/RiverInformation.js Line 13:6: React Hook useEffect has a missing dependency: 'name'. Either include it or remove the dependency array react-hooks/exhaustive-deps Search for the keywords to learn more about each warning. To ignore, add // eslint-disable-next-line to the line before.
このエラーは、エフェクト内の関数に、明示的に設定していない依存関係があることを示しています。 この状況では、効果が機能しないことは明らかですが、propデータをコンポーネント内のステートフルデータと比較している場合があります。これにより、配列内のアイテムを追跡できなくなる可能性があります。
最後に行うことは、コンポーネントに防御プログラミングを追加することです。 これは、アプリケーションの高可用性を強調する設計原則です。 データが正しい形状でない場合や、APIリクエストからデータをまったく取得しない場合でも、コンポーネントが確実にレンダリングされるようにする必要があります。
アプリが現在のように、エフェクトはriverInformation
を受信した任意のタイプのデータで更新します。 これは通常オブジェクトになりますが、そうでない場合は、オプションのチェーンを使用して、エラーがスローされないようにすることができます。
RiverInformation.js
内で、オブジェクトドットチェーンのインスタンスをオプションのチェーンに置き換えます。 動作するかどうかをテストするには、デフォルトのオブジェクト{}
をuseState
関数から削除します。
async-tutorial / src / components / RiverInformation / RiverInformation.js
import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { getRiverInformation } from '../../services/rivers'; export default function RiverInformation({ name }) { const [riverInformation, setRiverInformation] = useState(); useEffect(() => { getRiverInformation(name) .then(data => setRiverInformation(data) ); }, [name]) return( <div> <h2>River Information</h2> <ul> <li>Continent: {riverInformation?.continent}</li> <li>Length: {riverInformation?.length}</li> <li>Outflow: {riverInformation?.outflow}</li> </ul> </div> ) } RiverInformation.propTypes = { name: PropTypes.string.isRequired }
ファイルを保存して閉じます。 これを行うと、コードがオブジェクトではなくundefined
のプロパティを参照している場合でも、ファイルはロードされます。
通常、防御プログラミングはベストプラクティスと見なされますが、応答を保証できない場合のAPI呼び出しなどの非同期関数では特に重要です。
このステップでは、Reactで非同期関数を呼び出しました。 useEffect
フックを使用して、再レンダリングをトリガーせずに情報をフェッチし、useEffect
配列に条件を追加して新しい更新をトリガーしました。
次のステップでは、コンポーネントがマウントされたときにのみコンポーネントが更新されるように、アプリにいくつかの変更を加えます。 これは、アプリがメモリリークを回避するのに役立ちます。
ステップ2—マウントされていないコンポーネントでのエラーの防止
この手順では、マウントされていないコンポーネントのデータが更新されないようにします。 非同期プログラミングではデータがいつ解決されるかわからないため、コンポーネントが削除された後にデータが解決されるリスクは常にあります。 マウントされていないコンポーネントのデータを更新することは非効率的であり、アプリが必要以上のメモリを使用しているメモリリークを引き起こす可能性があります。
この手順を完了すると、useEffect
フックにガードを追加して、コンポーネントがマウントされている場合にのみデータを更新することで、メモリリークを防ぐ方法がわかります。
現在のコンポーネントは常にマウントされるため、 DOM から削除された後、コードがコンポーネントを更新しようとする可能性はありませんが、ほとんどのコンポーネントはそれほど信頼性がありません。 これらは、ユーザーがアプリケーションを操作するときにページに追加され、ページから削除されます。 非同期関数が解決される前にコンポーネントがページから削除されると、メモリリークが発生する可能性があります。
問題をテストするには、App.js
を更新して、川の詳細を追加および削除できるようにします。
App.js
を開きます:
nano src/components/App/App.js
川の詳細を切り替えるボタンを追加します。 useReducer
フックを使用して、詳細を切り替える関数と、切り替えられた状態を格納する変数を作成します。
async-tutorial / src / components / App / App.js
import React, { useReducer, useState } from 'react'; import './App.css'; import RiverInformation from '../RiverInformation/RiverInformation'; function App() { const [river, setRiver] = useState('nile'); const [show, toggle] = useReducer(state => !state, true); return ( <div className="wrapper"> <h1>World's Longest Rivers</h1> <div><button onClick={toggle}>Toggle Details</button></div> <button onClick={() => setRiver('nile')}>Nile</button> <button onClick={() => setRiver('amazon')}>Amazon</button> <button onClick={() => setRiver('yangtze')}>Yangtze</button> <button onClick={() => setRiver('mississippi')}>Mississippi</button> {show && <RiverInformation name={river} />} </div> ); } export default App;
ファイルを保存します。 ブラウズを実行するとリロードされ、詳細を切り替えることができます。
川をクリックし、すぐに Toggle Details ボタンをクリックして、詳細を非表示にします。 Reactは、潜在的なメモリリークがあることを警告するエラーを生成します。
この問題を修正するには、useEffect
内の非同期機能をキャンセルまたは無視する必要があります。 RxJS などのライブラリを使用している場合は、useEffect
フックに関数を返すことで、コンポーネントがアンマウントされたときに非同期アクションをキャンセルできます。 それ以外の場合は、マウントされた状態を格納するための変数が必要になります。
RiverInformation.js
を開きます:
nano src/components/RiverInformation/RiverInformation.js
useEffect
関数内で、mounted
という変数を作成し、true
に設定します。 .then
コールバック内で、mounted
がtrueの場合、条件を使用してデータを設定します。
async-tutorial / src / components / RiverInformation / RiverInformation.js
import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { getRiverInformation } from '../../services/rivers'; export default function RiverInformation({ name }) { const [riverInformation, setRiverInformation] = useState(); useEffect(() => { let mounted = true; getRiverInformation(name) .then(data => { if(mounted) { setRiverInformation(data) } }); }, [name]) return( <div> <h2>River Information</h2> <ul> <li>Continent: {riverInformation?.continent}</li> <li>Length: {riverInformation?.length}</li> <li>Outflow: {riverInformation?.outflow}</li> </ul> </div> ) } RiverInformation.propTypes = { name: PropTypes.string.isRequired }
変数ができたので、コンポーネントがアンマウントされたときにそれを反転できるようにする必要があります。 useEffect
フックを使用すると、コンポーネントがアンマウントされたときに実行される関数を返すことができます。 mounted
をfalse
に設定する関数を返します。
async-tutorial / src / components / RiverInformation / RiverInformation.js
import React, { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { getRiverInformation } from '../../services/rivers'; export default function RiverInformation({ name }) { const [riverInformation, setRiverInformation] = useState(); useEffect(() => { let mounted = true; getRiverInformation(name) .then(data => { if(mounted) { setRiverInformation(data) } }); return () => { mounted = false; } }, [name]) return( <div> <h2>River Information</h2> <ul> <li>Continent: {riverInformation?.continent}</li> <li>Length: {riverInformation?.length}</li> <li>Outflow: {riverInformation?.outflow}</li> </ul> </div> ) } RiverInformation.propTypes = { name: PropTypes.string.isRequired }
ファイルを保存します。 そうすると、エラーなしで詳細を切り替えることができます。
アンマウントすると、コンポーネントuseEffect
が変数を更新します。 非同期関数は引き続き解決されますが、マウントされていないコンポーネントには変更が加えられません。 これにより、メモリリークが防止されます。
この手順では、コンポーネントがマウントされている場合にのみアプリの更新状態を作成しました。 useEffect
フックを更新して、コンポーネントがマウントされているかどうかを追跡し、コンポーネントがマウント解除されたときに値を更新する関数を返しました。
次のステップでは、コンポーネントを非同期的にロードして、コードを小さなバンドルに分割し、ユーザーが必要に応じてロードします。
ステップ3—Suspense
およびlazy
を使用したコンポーネントの遅延読み込み
このステップでは、コードをReactSuspense
とlazy
で分割します。 アプリケーションが大きくなるにつれて、最終的なビルドのサイズも大きくなります。 ユーザーにアプリケーション全体のダウンロードを強制するのではなく、コードを小さなチャンクに分割することができます。 React Suspense
およびlazy
は、webpackやその他のビルドシステムと連携して、ユーザーがオンデマンドでロードできるようにコードを小さな部分に分割します。 将来的には、Suspense
を使用して、APIリクエストを含むさまざまなデータを読み込むことができるようになります。
この手順を完了すると、コンポーネントを非同期でロードして、大きなアプリケーションをより小さく、より焦点を絞ったチャンクに分割できるようになります。
これまでは、データを非同期的にロードすることだけを扱ってきましたが、コンポーネントを非同期的にロードすることもできます。 このプロセスは、コード分割と呼ばれることが多く、コードバンドルのサイズを縮小するのに役立ちます。これにより、ユーザーがアプリケーションの一部のみを使用している場合でも、アプリケーション全体をダウンロードする必要がなくなります。
ほとんどの場合、コードを静的にインポートしますが、ステートメントの代わりに関数としてimport
を呼び出すことにより、コードを動的にインポートできます。 コードは次のようになります。
import('my-library') .then(library => library.action())
Reactは、lazyおよびSuspense
と呼ばれる追加のツールセットを提供します。 React Suspense
は、最終的にデータロードの処理に拡張されますが、今のところ、これを使用してコンポーネントをロードできます。
App.js
を開きます:
nano src/components/App/App.js
次に、lazy
とSuspense
をreact
からインポートします。
async-tutorial / src / components / App / App.js
import React, { lazy, Suspense, useReducer, useState } from 'react'; import './App.css'; import RiverInformation from '../RiverInformation/RiverInformation'; function App() { const [river, setRiver] = useState('nile'); const [show, toggle] = useReducer(state => !state, true); return ( <div className="wrapper"> <h1>World's Longest Rivers</h1> <div><button onClick={toggle}>Toggle Details</button></div> <button onClick={() => setRiver('nile')}>Nile</button> <button onClick={() => setRiver('amazon')}>Amazon</button> <button onClick={() => setRiver('yangtze')}>Yangtze</button> <button onClick={() => setRiver('mississippi')}>Mississippi</button> {show && <RiverInformation name={river} />} </div> ); } export default App;
lazy
とSuspsense
には2つの異なるジョブがあります。 lazy
関数を使用して、コンポーネントを動的にインポートし、変数に設定します。 Suspense
は、コードの読み込み中にフォールバックメッセージを表示するために使用する組み込みコンポーネントです。
import RiverInformation from '../RiverInformation/RiverInformation';
をlazy
の呼び出しに置き換えます。 結果をRiverInformation
という変数に割り当てます。 次に、{show && <RiverInformation name={river} />}
をSuspense
コンポーネントでラップし、<div>
をLoading Component
のメッセージでfallback
小道具にラップします。
async-tutorial / src / components / App / App.js
import React, { lazy, Suspense, useReducer, useState } from 'react'; import './App.css'; const RiverInformation = lazy(() => import('../RiverInformation/RiverInformation')); function App() { const [river, setRiver] = useState('nile'); const [show, toggle] = useReducer(state => !state, true); return ( <div className="wrapper"> <h1>World's Longest Rivers</h1> <div><button onClick={toggle}>Toggle Details</button></div> <button onClick={() => setRiver('nile')}>Nile</button> <button onClick={() => setRiver('amazon')}>Amazon</button> <button onClick={() => setRiver('yangtze')}>Yangtze</button> <button onClick={() => setRiver('mississippi')}>Mississippi</button> <Suspense fallback={<div>Loading Component</div>}> {show && <RiverInformation name={river} />} </Suspense> </div> ); } export default App;
ファイルを保存します。 その場合、ページをリロードすると、コンポーネントが動的にロードされていることがわかります。 読み込み中のメッセージを表示したい場合は、ChromeWebブラウザで応答をスロットルできます。
ChromeまたはFirefoxのネットワークタブに移動すると、コードがさまざまなチャンクに分割されていることがわかります。
各チャンクはデフォルトで番号を取得しますが、Create React Appをwebpackと組み合わせて使用すると、動的インポートによってコメントを追加することでチャンク名を設定できます。
App.js
で、import
関数内に/* webpackChunkName: "RiverInformation" */
のコメントを追加します。
async-tutorial / src / components / App / App.js
import React, { lazy, Suspense, useReducer, useState } from 'react'; import './App.css'; const RiverInformation = lazy(() => import(/* webpackChunkName: "RiverInformation" */ '../RiverInformation/RiverInformation')); function App() { const [river, setRiver] = useState('nile'); const [show, toggle] = useReducer(state => !state, true); return ( <div className="wrapper"> <h1>World's Longest Rivers</h1> <div><button onClick={toggle}>Toggle Details</button></div> <button onClick={() => setRiver('nile')}>Nile</button> <button onClick={() => setRiver('amazon')}>Amazon</button> <button onClick={() => setRiver('yangtze')}>Yangtze</button> <button onClick={() => setRiver('mississippi')}>Mississippi</button> <Suspense fallback={<div>Loading Component</div>}> {show && <RiverInformation name={river} />} </Suspense> </div> ); } export default App;
ファイルを保存して閉じます。 これを行うと、ブラウザが更新され、RiverInformation
チャンクに一意の名前が付けられます。
このステップでは、コンポーネントを非同期でロードします。 lazy
およびSuspense
を使用して、コンポーネントを動的にインポートし、コンポーネントのロード中にロードメッセージを表示しました。 また、読みやすさとデバッグを向上させるために、webpackチャンクにカスタム名を付けました。
結論
非同期機能は、効率的なユーザーフレンドリーなアプリケーションを作成します。 ただし、それらの利点には、プログラムのバグに発展する可能性のある微妙なコストが伴います。 これで、ユーザーに表示可能なアプリケーションを提供しながら、大きなアプリケーションを小さな部分に分割し、非同期データをロードできるツールができました。 この知識を使用して、APIリクエストと非同期データ操作をアプリケーションに組み込み、高速で信頼性の高いユーザーエクスペリエンスを作成できます。
Reactチュートリアルをもっと読みたい場合は、 Reactトピックページを確認するか、React.jsシリーズのコーディング方法ページに戻ってください。