ホームページ >ウェブフロントエンド >jsチュートリアル >React コンポーネントを分割することの重要性
まえがき:
React は、ユーザー インターフェイスを構築するための JAVASCRIPT ライブラリです。主に UI の構築に使用され、React を MVC の V (ビュー) と考える人が多いです。
react は、仮想 DOM テクノロジーを使用して Javascript と実際の DOM の間の対話を減らし、フロントエンドのパフォーマンスを向上させます。一方向のデータ フロー メカニズムを使用して、親コンポーネントは props を通じて子コンポーネントにデータを渡します。データ フローの方向が一目で明らかです。
コンポーネントの props または状態が変更されると、コンポーネントとそのサブコンポーネントは再レンダリングされ、vdom-diff されてデータ フローの相互作用が完了します。ただし、この仕組みはデータ量が多い場合など、場合によってはパフォーマンスに問題が生じる可能性があります。 React のパフォーマンスのボトルネックを分析し、react-addons-perf ツールを使用して React コンポーネント分割の重要性を説明しましょう。
react のパフォーマンスのボトルネック
react のパフォーマンスのボトルネックを理解するには、react のレンダリング プロセスを知る必要があります。そのレンダリングは 2 つのステージに分けることができます。
初期コンポーネント化
このステージでは、コンポーネントとそのすべてのサブコンポーネントの render メソッドが実行され、それによって仮想 dom の最初のバージョンが生成されます。
コンポーネントのレンダリングの更新。
コンポーネントのプロパティまたは状態が変更されると、コンポーネントの更新レンダリングがトリガーされます。デフォルトでは、コンポーネントとそのすべてのサブコンポーネントの render メソッドも実行して、新しい仮想 DOM を取得します。
私たちが話しているパフォーマンスのボトルネックとは、コンポーネントの更新フェーズ中の状況を指します。
反応コンポーネントの更新プロセス
上記の分析により、コンポーネント更新の具体的なプロセスは次のとおりであることがわかります。
コンポーネントの render メソッドとすべてのレンダリング メソッドを実行します。子コンポーネントを更新する必要がない場合でも、そのサブコンポーネントは更新された仮想 DOM を取得します。つまり、再レンダリングされます。
次に、古い仮想 DOM と新しい仮想 DOM を比較してコンポーネントを更新します。
このプロセスでは、コンポーネントの shouldComponentUpdate メソッドの戻り値を通じて再レンダリングが必要かどうかを判断できます。
React の更新レンダリング プロセス全体を図で説明します。
デフォルトでは、コンポーネントの shouldComponentUpdate は true を返します。つまり、React はすべてのコンポーネントの render メソッドは新しい仮想 DOM を生成し、それを古い仮想 DOM と比較して、コンポーネントを最終的に更新する必要があるかどうかを判断します。
反応のパフォーマンスのボトルネック
画像で話しましょう。たとえば、下の画像はコンポーネント構造ツリーです。サブコンポーネントを更新したい場合は、下の画像の緑色のコンポーネントが必要です(ルート コンポーネントからアプリケーションに渡されます。緑のコンポーネント上のデータが変更されます):
理想的には、次のように、クリティカル パス上のコンポーネントのみを更新する必要があります。以下:
ただし、実際の効果は、コンポーネントは変更されていないにもかかわらず、各コンポーネントが再レンダリングと仮想 DOM の差分プロセスを完了することです。これは明らかに無駄です。 。以下の図に示すように、黄色の部分は無駄な再レンダリングと仮想 DOM の差分を表します。
上記の分析によると、react のパフォーマンスのボトルネックは主に次の点で明らかになります。
props と state が変更されていないコンポーネントの場合、react には次のようなニーズもあります。仮想 DOM と仮想 DOM の差分を再生成します。
パフォーマンスの最適化に shouldComponentUpdate を使用する
react のパフォーマンスのボトルネックに対応して、react が提供する shouldComponentUpdate メソッドを使用して最適化を行うことができます。コンポーネントを選択的に更新して、react を改善できます。
shouldComponentUpdate は、現在のプロパティとステータスが前回と同じかどうかを判断する必要があり、同じであれば、その後の仮想 DOM とそのステータスの生成プロセスを実行する必要はありません。 diff でない場合は、更新する必要があります。
(学習ビデオ共有: javascript ビデオ チュートリアル)
具体的な実装は次のように表示できます:
shouldComponentUpdate(nextProps, nextState){ return !isEqual(nextProps, this.props) || !isEqual(nextState, this.state) }
その中で、 isEqual メソッドは2 つのオブジェクトが等しいかどうかを判断します (オブジェクトの内容が一致するのではなく、等しいという事実を指します)。
無駄な更新を避けるために、オーバーライドの shouldComponentUpdate メソッドを表示して、コンポーネントを更新する必要があるかどうかを判断します。ただし、このメソッドを各コンポーネントに追加するのは面倒です。幸いなことに、react は公式のソリューションを提供します。具体的な方法は次のとおりです:
このソリューションは、コンポーネントの shouldComponentUpdate をカプセル化し、コンポーネントの現在のプロパティおよびステータスと以前のものとの浅い比較を実装して、コンポーネントを更新する必要があるかどうかを判断します。
react は、開発のさまざまな段階で 2 つの公式ソリューション セットを提供します。
PureRenderMin
1 つは、ES5 の React.createClass に基づいて作成されたコンポーネントで、このコンポーネントの mixins メソッドと組み合わせられます。フォーム。PureRenderMixin によって提供される shouldComponentUpdate メソッド。もちろん、ES6 で作成されたコンポーネントでもこのソリューションを使用できます。
PureComponent
このソリューションは、React 15.3.0 バージョンでリリースされた ES6 に追加されたコンポーネント基本クラスです: React.PureComponent。これは明らかに、ES6 の方法で作成されたコンポーネントにとってよりフレンドリーです。
PureRenderMin であっても PureComponent であっても、内部の shouldComponentUpdate メソッドはプロパティと状態オブジェクトを浅く比較 (shallowCompare) します。つまり、最初のオブジェクトのみを比較することに注意してください。オブジェクトの属性とその値が同じかどうか。たとえば、次の state オブジェクトは次の値に変更されます。
state の値は別のオブジェクトに割り当てられるため、nextState.value と this.props.value は次のようになります。常に等しくないため、浅い結果になります。 比較は失敗しました。実際のプロジェクトでは、このようなネストされたオブジェクトの結果はよくあることですが、PureRenderMin メソッドや PureComponent メソッドを使用すると、期待した効果が得られません。
深い比較によって判断できますが、深い比較は再帰的な操作であるディープ コピーに似ており、パフォーマンスのオーバーヘッドが比較的大きくなります。
この目的のために、コンポーネントをできるだけ分割して、コンポーネントのプロパティと状態オブジェクト データを平坦化します。PureRenderMin または PureComponent を使用してコンポーネントが更新されたかどうかを判断することと組み合わせると、パフォーマンスをより向上させることができます。の反応. は、開発者があまり気にする必要はありません。
コンポーネントの分割
react におけるコンポーネントの分割は、再利用と最適化を容易にするためにコンポーネントを可能な限り細分化することです。分割の具体的な原則:
分割コンポーネントが更新するかどうかを判断しやすくするようにしてください
これは簡単ではありません。例を示します: 親コンポーネントを定義するとします。 5000 個のサブコンポーネントが含まれています。インプットボックスの入力操作があり、数字を入力するたびに、対応するサブコンポーネントの背景色が赤色に変わります。
この例では、入力ボックス コンポーネントとリスト サブコンポーネントは明らかに異なります。1 つは動的で入力値の頻度が高く、もう 1 つは相対的なものです。入力に関係なく静的です。5000 項目と入力します。入力ボックスに数値が入力されるたびに、すべてのコンポーネントが再レンダリングされ、リストのサブコンポーネントが不必要に更新されます。
入力コンポーネントとリスト サブコンポーネントの状態は親コンポーネントの状態に配置され、共有されているため、上記のリスト コンポーネントの更新をキャンセルするのは簡単ではないことがわかります。 React が shouldComponentUpdate の戻り値を使用することは不可能です。コンポーネントの一部を更新し、他の部分を更新しません。それらを異なるコンポーネントに分割することによってのみ、各コンポーネントは対応する props のみを考慮するようになります。分割リストコンポーネントは自身の属性のみを気にしており、他のコンポーネントは親コンポーネントの更新を引き起こしますが、リストコンポーネントでは気になる属性値を判断して更新するかどうかを決めることができるので、コンポーネントをより適切に最適化できます。
分割されたコンポーネントのプロパティと状態データを平坦化してみる
これは主にコンポーネントの最適化の観点から考慮されます。コンポーネントがパフォーマンスにあまり注意を払う必要がない場合は、無視される。
分割コンポーネントがフラットになる理由は、React が提供する最適化ソリューション PureRenderMin または PureComponent がコンポーネントのプロパティと状態を浅く比較して、コンポーネントを更新するかどうかを決定するためです。
上記のリスト コンポーネントでは、this.state.items にオブジェクトの配列が格納されています。各リストを更新する必要があるかどうかをより適切に判断するために、各 li リスト項目をリスト項目コンポーネントに分割できます。各リスト項目に関連するプロパティは、項目配列内の各オブジェクトです。このフラットなデータにより、データが変更されたかどうかを簡単に判断できます。
コンポーネント分割の例
この記事では、Todo リストの追加と表示に関するケース ライブラリを作成しました。コードをローカルにクローンして、エフェクトをローカルで実行します。
ケースライブラリは5,000件のTodoリストであり、Todo項目の削除・追加が可能です。この例は、コンポーネント分割の前後でのエクスペリエンスを比較したもので、パフォーマンスが大幅に向上していることがわかります。
以下では、react-addons-perf パフォーマンス テスト ツールを組み合わせて、コンポーネントの分割状況を示します。
分割前のコンポーネント TodosBeforeDivision のレンダリング部分は次のとおりです。
コンポーネントを分割する前に、入力ボックスに文字を入力できます。次の図に示すように、todo または todo 項目を削除すると、明らかな遅れがあることがわかります:
#遅れの原因を突き止めるために、次のことを行います。 Chrome の devTool を使用して見つけます。その方法は、Chrome ブラウザの最新バージョンのパフォーマンス オプションを使用することです。まず、このオプションの [記録] ボタンをクリックして記録を開始します。このとき、コンポーネント入力ボックスに文字を入力し、[停止] をクリックして記録を停止します。コンポーネントの最初から最後までのパフォーマンス プロファイルが表示されます。入力。
#図からわかるように、単一の文字を入力すると、入力ボックスの入力イベント ロジックが応答時間のほぼ全体を占めます。これは主に反応レベルのbatchedUpdatesメソッドで、ユーザー定義のロジックではなくリストコンポーネントをバッチで更新します。 それでは、なぜバッチ更新にこれほど時間がかかるのでしょうか? その理由を理解するために、react-addons-perf をベースにした chrome プラグイン chrome-react-perf を使用します。クロムプラグインの形式。 このプラグインを使用する際の注意点は次のとおりです: chrome-react-perf プラグインを使用するには、プロジェクトにreact-addons-perf モジュールを導入する必要があります。であり、そのオブジェクトはグローバル オブジェクトの Perf 属性のウィンドウにマウントされている必要があります。そうでない場合は使用できません。 devTool ツールで Perf オプション ビューを選択し、開始ボタンをクリックすると停止ボタンになり、コンポーネント入力ボックスに文字を入力して、Perf ビューの停止ボタンをクリックします。対応するパフォーマンス試行を取得します。 上の図に示されている 4 つのビューのうち、Print Wasted はパフォーマンスの分析に最も役立ちます。これは、コンポーネントが変更されていないものの、更新プロセスに参加していることを示します。つまり、render と vdom-diff のプロセスは無駄になります。無意味なプロセスです。図からわかるように: TodosBeforeDivision コンポーネントと TodoItem コンポーネントはそれぞれ 167.88 ミリ秒と 144.47 ミリ秒を無駄にしました。このオーバーヘッドはコンポーネントを分割することで回避できます。これが反応パフォーマンスの最適化の焦点です。 このためには、TodosBeforeDivision コンポーネントを、入力とボタンを備えた動的コンポーネント AddTodoForm と、比較的静的なコンポーネント TodoList に分割する必要があります。不要なコンポーネントの更新を避けるために、どちらもそれぞれ React.PureComponent を継承します。 TodoList コンポーネントは、各 Todo タスクのコンポーネント TodoItem に分割する必要もあります。これにより、各 TodoItem コンポーネントの props オブジェクトはフラット データになり、React は完全にデータ化できるようになります。 .PureComponent は、オブジェクトの浅い比較を実行して、コンポーネントを更新する必要があるかどうかをより適切に判断するために使用されます。これにより、TodoItem アイテムが追加または削除されたときに他の TodoItem コンポーネントを更新する必要がなくなります。 このようにコンポーネントを分割した後、上記のパフォーマンス テスト ツールを使用して、対応する効果を確認します。 上のスクリーンショットからわかるように、分割コンポーネントのパフォーマンスは何百倍も向上していますが、コンポーネントの属性位置にバインドしないことや、再実行を避けるために定数オブジェクト プロパティをキャッシュすることなど、他の最適化も含まれています。レンダリング時に新しい関数と新しいオブジェクト プロパティを再生成します。 一般に、反応コンポーネントの分割は反応パフォーマンスを向上させるために非常に重要であり、これは反応パフォーマンスの最適化の方向性でもあります。 関連する推奨事項:以上がReact コンポーネントを分割することの重要性の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。