ライフサイクル
ライフサイクルとは何ですか
一言で言えば、創造から破壊までのプロセスがライフサイクルです
では、反応ライフサイクルの段階は何でしょうか?
- 初期化フェーズ
constructor
コンストラクター
getDefaultProps
プロパティのデフォルト値
getInitialState
状態のデフォルト値 - マウント フェーズ
componentWillMount
コンポーネントの初期化とレンダリングの前に呼び出されます
render
コンポーネントのレンダリング
componentDidMount
コンポーネントが DOM にマウントされた後に呼び出されます< /span> - 更新フェーズ
componentWillReceiveProps
コンポーネントが新しいプロパティを受け取る前に呼び出されます。
shouldComponentUpdate
コンポーネントを更新する必要があるかどうか。
componentWillUpdate
呼び出されます。コンポーネントが更新される前
render
コンポーネントのレンダリング
componentDidUpdate
コンポーネントの更新後に呼び出されます - 荷降ろし段階
componentWillUnmount
React16 の新しいライフサイクルでは、3 つのメソッド componentWillMount
、componentWillReceiveProps
、componentWillUpdate
が廃止され、 が追加されました。 a>) これら 3 つのフックは React16 では削除されていません。ただし、これと混合することはできません。新しいフック関数。React17 ではこれら 3 つのフック関数が削除され、新しいエラー処理 ( 3 つの非推奨のフック関数を置き換えます。 getDerivedStateFromProps
、getSnapshotBeforeUpdate
componentDidCatch
では、新しい方法をどのように使用すればよいのでしょうか?
getDerivedStateFromProps
: コンポーネントが再レンダリングされるたび (コンポーネントのビルド後 (仮想 dom の後、実際の dom がマウントされる前) を含む)、新しい props または state が取得されるたびに返されます。新しい props を受け取ります。オブジェクトは新しい状態として機能します。null を返すことは、状態を更新する必要がないことを意味します。componentDidUpdate
を使用すると、componentWillReceiveProps
。
getSnapshotBeforeUpdate
: トリガー時間: 更新が発生したとき、レンダリング後およびコンポーネント DOM レンダリング前。componentDidUpdate
の 3 番目のパラメータとして値を返します。< a i=2> と連携します。 、 のすべての使用法をカバーできます。 componentDidUpdate
componentWillUpdate
componentDidCatch
: ライフサイクル メソッドまたは子コンポーネントのレンダリング フェーズ中に何らかのエラーが発生した場合、componentDidCatch
() メソッドが呼び出されます。このメソッドは、React アプリケーションのエラー境界を実装するために使用されます。これはコミット フェーズ中に呼び出されるため、レンダリング フェーズ中に呼び出される getDerivedStateFromError
() とは異なり、このメソッドでは side-effects
を使用できます。このメソッドはエラーをログに記録するためにも使用されます。 2 つのパラメータ error
と info
を受け取ります; error
: これは子孫コンポーネントによって発生するエラーです。 info
: このエラーの原因となったコンポーネントのcomponentStack
トレースが保存されます。
副作用
-
最初に説明します
纯函数(Pure function)
: 関数に同じパラメータを与えると常に同じ値が返され、副作用はありません。この概念を React に適用すると、関数を与えることになります。 < a i=2> 同じ であり、常に同じビューをレンダリングし、他の副作用はありません。純粋なコンポーネントの利点は、データの変更を監視しやすいことです。レンダリング パフォーマンスのテストや改善などを行うため; a>Pure component
props
-
副作用 (
Side Effect
) とは、グローバル変数の変更、渡されたパラメータの変更、またはconsole.log()
であっても、ajax
操作と変更dom
は副作用とみなされます。
仮想ドーム
仮想Domの定義
これは本質的には JS オブジェクトであり、DOM をより軽量に記述したものです。
React は、DOM 操作の問題点を解決するために、常にページ全体を更新するという新しいアイデアを提案しており、前後の状態変化が発生した場合、React は UI を自動的に更新しますが、欠点は、その更新が非常に難しいことです。遅い。したがって、変更されていない DOM ノードは変更されずに残され、変更された DOM ノードのみが作成および置換されてノードの再利用が実現されるため、問題は 2 つの DOM ノードの違いを比較する方法に変換されます。 DOM はツリーの分解であるため、完成したツリー構造の差分アルゴリズムの複雑さは O(n^3) です。
React では、複雑さを軽減するために 3 つの最適化が行われています。
- 親ノードが異なる場合は、子ノードの比較を放棄し、古いノードを直接削除し、再レンダリングする新しいノードを追加します。
- 子ノードが変更された場合、VirtualDOM は変更を計算せず、2 回再レンダリングしません。
- 一意のキー値を設定してノードを比較します。実際の DOM には多くの属性があり、そのほとんどは DIff には役に立たないため、より軽量な JS オブジェクトを使用して複雑な DOM ノードを置き換えると、大量のクエリ操作を回避できます。 DOM上で。
Virtual Domの役割
- パフォーマンスは多少犠牲になりますが、保守性は向上します。
- フレームワークをクロスプラットフォームにできる
- コンポーネントの高度な抽象化
仮想 Dom の欠点
- 大量の DOM を初めてレンダリングする場合は、複数のレイヤーの仮想 DOM を計算するため、多少時間がかかります。
- DOM のコピーをメモリ内に保持する必要がある
- これは、仮想 DOM が大幅に変更される場合に適しています。ただし、単一の頻繁な更新の場合、仮想 DOM は計算の処理により多くの時間を費やします。したがって、ページ数が比較的少ない DOM ノードがある場合、実際には仮想 DOM を使用すると速度が低下する可能性があります。
setState
メカニズム
setState
同期ですか、それとも非同期ですか?
React のライフサイクルと合成イベントでは、React はまだ更新メカニズムにあります。何度呼び出されてもsetState
、更新はすぐには実行されません。更新された値は_pendingStateQueue
に格納され、更新されるコンポーネントはdirtyComponent
に格納されます。
ライフサイクルを例に挙げると、最後の更新メカニズムが完了すると、すべてのコンポーネント、つまり最上位コンポーネントがバッチ フラグを設定します。 didmount
偽に。このとき、dirtyComponent
のコンポーネントと_pendingStateQueue
の状態が取り出して更新されます。これにより、コンポーネントが複数回再レンダリングされることがなくなります。
componentDidMount() {
this.setState({
index: this.state.index + 1
})
console.log('state', this.state.index);
}
そのため、上記のコードのように、setState
を実行した直後に state
を取得すると、更新されたバージョンを取得できません a>< a i=3> は React のバッチ処理機構内にあるため、 は一時的に保存され、バッチ処理機構が完了した後に一律に更新されます。 それで。 自体は非同期ではありませんが、React のバッチ処理メカニズムにより非同期であるかのような錯覚が生じます。 state
state
setState
非同期コードとネイティブ イベントの場合:
componentDidMount() {
setTimeout(() => {
console.log('调用setState');
this.setState({
index: this.state.index + 1
})
console.log('state', this.state.index);
}, 0);
}
上記のコードのように、setState
を非同期コードで呼び出すと、JavaScript の非同期メカニズムに従って、非同期コードは最初に一時的に保存され、その後処理されます。同期コードが実行されます。実行します。この時点で、React のバッチ処理機構が完了し、処理フラグが false
に設定されます。このとき、 setState
を呼び出します。もう一度実行すると、すぐに更新が実行され、更新された結果が得られます。
ネイティブ イベントで setState
を呼び出しても、React のバッチ処理メカニズムはトリガーされないため、最新の結果をすぐに取得できます。
ベスト プラクティス
setState
の 2 番目のパラメータは、React のバッチ処理メカニズムが完了した後に呼び出される関数を受け取るため、setState
Get the値はすぐに更新されます。このコールバック関数で取得してください
setState
新しいステータスを受け取る- 受信した新しいステータスはすぐには実行されませんが、
pendingStates
(待機キュー) に保存されます。
setState
実行原理は、
次の 2 つのカテゴリに分類できます。
- バッチ更新クラス: つまり、
react
の内部実行関数とsetState
の実行ロジックは、以下を含むバッチ更新処理です。 内部イベントの反応(合成イベント) とライフサイクル; - 非バッチ更新タイプ: 上記 2 つの状況以外の状況。一般的に見られる状況: ネイティブ イベント、
setTimeout
、fetch
など。
2 つのコンセプト:
- トランザクション: 通常の関数が別のレイヤーにラップされていることがわかります。パッケージ処理のこの層には、関数の実行前の 1 つ以上の処理関数 (初期化関数) と、関数の実行後の 1 つ以上の処理関数 (close 関数) が含まれます。React の多くの論理処理ではトランザクションの概念が使用されます。
- 合成イベントとネイティブ イベントの関係と違い:
違い: ネイティブ イベントは、addEventListener 方式で記述されたイベントです。合成イベントは、onClick、onChange などを React に直接書き込むことです。
関係: 合成イベントは、React によるネイティブ イベントのラッピングとして理解できます。ネイティブ イベントは、は上記のトランザクション概念における通常の関数に相当し、パッケージ化処理後に形成されるトランザクションがreactにおける合成イベントとなります。
ネイティブ イベントでは、setState
は render
更新を直接トリガーするため、ネイティブ イベントでのサンプルの実行順序は最初です。 a>などの更新後のステータスなので、上記のネイティブイベントの出力順が表示されていて非常にわかりやすいです。 トランザクションが実行され、その後印刷が実行されます。出力されるのは、render
次に実行callback
setState
setState
これは合成イベントの場合には当てはまりません。トランザクション 1 が直接開始され、関数が実行される前にバッチでステータスの更新が開始されます (isBatchedUpdates
は true
、デフォルト値は false
!)、オンにした後、合成イベントで setState
を実行します。このとき、一括更新状態になります。 、setState
は現時点ではトリガーされません。render
更新では、代わりに 2 つのことを実行します: state
と を収集します。 callback
。
バッチ更新はデフォルトでオフになっており、その後は直接実行されますbatchedUpdates
(この関数は更新レンダリング関数です)。ここでは、バッチ更新ステータスが有効かどうかの分岐点を示します。バッチ更新が有効な場合、ステータス push
が配列 (dirtyComponents
) に追加されます。
ステータスを収集した後、トランザクションを実行する close
関数は何を行いますか? 1 つはバッチ更新ステータスを閉じること、もう 1 つは収集されたステータスの処理を正式に開始することです。ここでは、新しいトランザクション (トランザクション 2) が開かれます。トランザクション 2 は、複雑な処理の後、収集された状態、つまり dirtyComponents
を更新します。処理後、トランザクション 2 の close
関数が実行され、更新された状態全体がリセットされます。これもトランザクション 1 で収集されます。 callback
; ; a>
总结setState
:
setState
実行は 2 つの主要なカテゴリに分けられます: 1 つはライフ サイクルと合成関数、もう 1 つは以前とは異なる 2 つの状況です。- 両方のタイプ、
setState
は同期的に実行されますが、バッチ更新クラスでは、state
とcallback
が収集されますこれは、データの非同期実行として理解でき、バッチ更新クラスのsetState
の代わりに、更新レンダリングを直接トリガーします。 callback
とstate
は同時に収集され、render
の後に均一に処理されます。
合成イベントのメカニズムと原理
fiber
メカニズムの特性により、ファイバー ノードの生成時に、対応する dom
ノードがまだマウントされていない可能性があります。< a i=3> などのイベント処理関数は ノードの として使用されるため、実際の DOM ノードに直接バインドすることはできません。 この目的のために、React は「トップレベルの登録、イベント収集、統合トリガー」というイベント メカニズムを提供します。 onClick
fiber
prop
いわゆる「トップレベル登録」は、実際には、統合イベント処理を root
にバインドします。要素関数。 「イベント収集」とは、イベントがトリガーされたとき (実際には root
上のイベント処理関数が実行されたとき) を指します。合成イベント オブジェクトを作成し、バブリング パスまたはキャプチャ パスに従ってコンポーネント内の実際のイベント処理関数を収集します。 「統合トリガー」は収集プロセスの後に発生し、収集されたイベントは 1 つずつ実行され、同じ合成イベント オブジェクトを共有します。ここで重要な点は、root
にバインドされているイベント リスナーは、コンポーネント内に記述したイベント処理関数ではないということです。この違いについては、後述するので注意してください。
上記は React イベント メカニズムの簡単な説明です。このメカニズムにより、イベントを DOM ノードに直接バインドできないという問題が回避され、fiber
イベントの階層を有効に活用できます。ツリー関係を使用してイベント実行パスを生成し、それによってイベント キャプチャとバブリングをシミュレートし、さらに 2 つの非常に重要な機能ももたらします。
イベントの分類には、イベントによって生成されたタスクのさまざまな優先順位を含めることができます。
合成イベント オブジェクトを提供してブラウザーの互換性の違いを解消します。
次に、イベントの登録から実行までのライフサイクル全体を通して、イベントの仕組みを詳しく説明します。
- イベント処理関数はコンポーネントの要素ではなくルートにバインドされており、これはファイバーツリーの構造上の特性に関係しており、イベント処理関数はファイバーの小道具としてのみ使用できます。
- ルートにバインドされるイベント リスナーは、コンポーネントに記述したイベント ハンドラー関数ではなく、イベントの優先度を保持し、イベント実行ステージ フラグを渡すことができるリスナーです。
合成イベントオブジェクト
コンポーネント内のイベント処理関数で取得したイベント オブジェクトはネイティブのイベント オブジェクトではなく、React によって合成されたオブジェクトですSyntheticEvent
。異なるブラウザ間の互換性の違いを解決します。それを統合イベント オブジェクトに抽象化し、開発者の精神的な負担を軽減します。
ファイバ
多数の同時計算タスクにより、ブラウザの UI レンダリングがブロックされます。デフォルトでは、JS 操作、ページ レイアウト、ページ描画はすべてブラウザのメイン スレッドで実行され、相互に排他的です。 JS 操作がメイン スレッドを占有し続けると、ページの更新が間に合わなくなります。ページを更新するために setState
を呼び出すと、React はアプリケーションのすべてのノードを走査し、差異を計算して、UI を更新します。プロセス全体は一度に実行され、中断することはできません。ページ要素が多い場合、プロセス全体に 16 ミリ秒以上かかる可能性があり、フレーム ドロップが発生しやすくなります。
メインスレッドが JS 操作によって長時間占有されるという問題を解決するための基本的なアイデアは、操作を複数のステップに分割し、バッチで完了することです。つまり、タスクの一部が完了すると、制御がブラウザに返され、ブラウザがページをレンダリングできるようになります。ブラウザが終了するまで待ってから、未完了のタスクを続行します。
window.requestIdleCallback()
ブラウザーがアイドル状態のときに関数が順次呼び出されるため、開発者は、アニメーションやユーザー インタラクションなどの遅延はあるものの重要なイベントに影響を与えることなく、メイン イベント ループでバックグラウンド タスクや優先度の低いタスクを実行できます。関数は通常、ブラウザーが呼び出す前に関数のタイムアウトが切れない限り、先入れ先出しの順序で実行されます。
React フレームワークの内部操作は 3 つの層に分けることができます。
- ページがどのように見えるかを記述する仮想 DOM レイヤー。
- Reconciler レイヤーは、コンポーネントのライフサイクル メソッドの呼び出し、Diff 操作の実行などを担当します。
- レンダラ層は、さまざまなプラットフォームに応じて対応するページをレンダリングします。より一般的なものは ReactDOM と ReactNative です。
react16 以降のバージョンでの最大の変更点は、間違いなく Reconciler レイヤーです。React チームは、これに Fiber Reconciler という新しい名前も付けました。
Fiber Reconciler の実行プロセスは 2 段階に分かれます。
- 最初の段階では、ファイバー ツリーが生成され、更新する必要があるノード情報が取得されます。このステップは段階的なプロセスであるため、中断することができます。
- 第 2 段階では、更新が必要なノードが一度にバッチで更新され、このプロセスは中断できません。
フェーズ 1 の割り込み可能機能により、優先度の高いタスクが最初に実行されるため、ページ フレームがフレームワーク レベルからドロップされる可能性が大幅に減少します。
Fiber Reconciler がステージ 1 で Diff 計算を実行すると、Fibre ツリーが生成されます。このツリーは、Virtual DOM ツリーをベースに追加情報を追加して生成されたもので、本質的にはリンク リストです。
ファイバー ツリーは、初回レンダリング時に一度に生成されます。後で Diff が必要になった場合、既存のツリーと最新の Virtual DOM 情報に基づいて新しいツリーが生成されます。この新しいツリーで新しいノードが生成されるたびに、制御がメイン スレッドに返され、実行する必要がある優先度の高いタスクがあるかどうかがチェックされます。そうでない場合は、ツリーの構築プロセスを続行します。
プロセス中に実行する必要がある優先度の高いタスクがある場合、Fibre Reconciler は生成中のツリーを破棄し、アイドル状態になったときに再度実行します。
ファイバー ツリーの構築プロセス中に、Fibre Reconciler は更新が必要なノード情報をエフェクト リストに保存します。フェーズ 2 が実行されると、該当するノードがバッチで更新されます。
ファイバーはどのように実装されますか?
链表、一次Fiber循环所有节点访问两次、requestIdleCallback
繊維についての深い理解
必要
1. 每一个状态的改变不是都需要马上反应在UI界面上
2. 不同的状态改变应该有不同的优先级,如动画,输入等应该有更高的优先级
3. 对于大量状态的改变复杂操作应该进行更好的调度,避免UI页面卡顿
繊維構造
ファイバー ツリーの全体構造は双方向の循環リンク リストであり、この構造により対応するノードをより迅速に見つけることができます。
調整プロセス中に前のノードの情報を知るには、新しいファイバー ノードを古いファイバー ノードに関連付ける必要があります。
Fiber には同時に 2 つのファイバー ツリーが存在します。各 Reconcile のプロセスは、新しいファイバー ツリーを構築するプロセスです。コミット後、新しいファイバー ツリーが現在のファイバー ツリーになります。等々。 。
ファイバー効果
調整プロセス中に、ノードは古いノードと比較する必要がある状態に設定される必要があります。各ファイバー ノードが構築された (独自のeffectTag ステータスを設定した) 後、エフェクトがある場合、それ自体とその子孫要素が親ノードのエフェクトに配置されます。このようにして、レイヤーごとに、すべてのエフェクトが保存されます。新しいファイバー ツリー内で処理されるファイバー ノード。次に、コミット ステージに入り、すべてのファイバー ノードを dom に変換し、UI ページを更新します。
ファイバースケジューリング
Fiber は仮想スタックであるため、スケジュールする必要があります。この関数を使用して、ブラウザがアイドル状態のときにコードを実行し、ページのレンダリングをブロックしないようにすることができます。
ファイバーの優先順位
ユーザー エクスペリエンスを向上させるには、アニメーションや入力など、優先度の高いタスクを最初に実行する必要があります。 Fiber には 5 つの優先順位があり、各優先順位は有効期限に対応します。
タイム スライシングとは、平たく言えば、タスクをいくつかのタイプに分割することを意味します。具体的には、
- すぐに実行する必要があるタスク
- ユーザーが非アクティブな間に実行する必要があるタスク
- 通常のタスク
- 優先度の低いタスク
- ブラウザがアイドル状態のときに実行されるタスク
優先度に従って実行します。新しいタスクが挿入されると、優先度に従って並べ替えられます。
このモジュールは、2 つの新しい es6 API を使用して実装されます。 >をご覧ください。各サイクルで、期限切れのタスクがある場合は、期限切れのタスクを何としても実行する必要があり、時間が残っている場合は、期限切れ時間の小さいタスクが最初に実行されます。 。具体的な使用方法はwindow.requestAnimationFrame
と window.requestIdleCallback
MDN