React における useEffect と useLayoutEffect の違い

React における useEffect と useLayoutEffect の違い

前提条件

React のワークフローはいくつかの部分に分けることができます。

  1. レンダリングフェーズ: 主にファイバーノードを生成し、完全なファイバーツリーを構築します。
  2. コミットフェーズ: 前のレンダリングフェーズでは、ルートファイバー上に副作用リストが生成され、このフェーズでアプリケーションのDOM操作が実行されます。

コミットフェーズでの作業は主に 3 つの部分に分かれており、ソースコード内の対応する関数名は次のとおりです。

  • commitBeforeMutationEffectsフェーズ: 主にDOM操作を実行する前にいくつかの関連操作を処理します。
  • commitMutationEffectsフェーズ: DOM操作の実行
  • commitLayoutEffectsフェーズ: 主にDOM操作を実行した後の関連する操作を処理します。

useEffect と useLayoutEffect の違いは、主にこれら 3 つの段階の処理にあります。結論としては、useEffect はレスポンス関数と最後の破棄関数を非同期的に実行しますが、useLayoutEffect はレスポンス関数と最後の破棄関数を同期的に実行し、DOM レンダリングをブロックします。

使用効果

コミット前ミューテーション効果

この段階では、useEffect は次の文に焦点を当てます。

関数 commitBeforeMutationEffects() {
  (nextEffect$1 !== null) の間 {
    // 一連の代入演算は省略されています。ここでのフラグは、対応する FunctionComponent の effect のフラグから取得する必要があります。具体的な実装については、ソースコードを参照してください。var flags = effect.flags;

  // 処理ライフサイクル if ((flags & Snapshot) !== NoFlags) {
      現在のファイバーを設定します(次の効果$1);
      commitBeforeMutationLifeCycles(現在の効果、次の効果$1);
      現在のファイバーをリセットします。
    }

 // この if 文は useEffect が true で useLayoutEffect が false かどうかのみをチェックします
    if ((フラグ & Passive) !== NoFlags) {
      // パッシブ効果がある場合は、フラッシュするコールバックをスケジュールします
      // 最も早い機会。
      ルートに受動的な効果がある場合
        rootDoesHavePassiveEffects = true;
 // これが useEffect が非同期である理由です。React は DOM 操作の後に flushPassiveEffects をスケジュールします。
        スケジュールコールバック(NormalPriority、関数() {
          PassiveEffects をフラッシュします。
          null を返します。
        });
      }
    }

    次のエフェクト$1 = 次のエフェクト$1.次のエフェクト;
  }
}

コミットミューテーション効果

このフェーズでは、React は一連の DOM ノード更新を実行し、次のメソッドを実行します: commitHookEffectListUnmount(HookLayout | HookHasEffect, finishedWork);

すると、useEffect を持つ Functional Component は、この段階ではアンマウント判定ロジックに準拠していないため、この場所ではアンマウント操作は実行されません。

コミットレイアウト効果

この段階では、まだ非常に重要なメソッドが残っています: commitHookEffectListMount(HookLayout | HookHasEffect, finishedWork);

この if 判定は前の段階の if 判定と同じです。useEffec はこの判定では何も操作を行いません。

その後の段階

commitLayoutEffects を完了した後、もう 1 つの操作があります。

ルートに受動的な効果がある場合
    // このコミットには受動的な効果があります。それらへの参照をスタッシュします。ただし、
    // レイアウト作業がフラッシュされるまでコールバックをスケジュールします。
    rootDoesHavePassiveEffects = false;
    rootWithPendingPassiveEffects = ルート;
    pendingPassiveEffectsLanes = レーン;
    pendingPassiveEffectsRenderPriority = renderPriorityLevel;
  }

つまり、rootWithPendingPassiveEffects は root に設定されます。この理由は、最初のフェーズ commitBeforeMutationEffects で useEffect によって登録された次の flushPassiveEffects 非同期スケジュールに関連しています。次の flushPassiveEffects 実装を見てみましょう。

関数flushPassiveEffectsImpl() {
 ルートがPendingPassiveEffectsの場合、nullになります。
    false を返します。
  }
 //一連のパフォーマンス追跡操作を省略する commitPassiveUnmountEffects(root.current);
  PassiveMountEffects をコミットします (ルート、ルート.current)。
}


上記のコード スニペットからわかるように、最初のフェーズで useEffect によって登録されたスケジュール コールバックは、ページが更新された後にアンマウントされ、マウントされます。このコールバックのエフェクトは commitLayoutEffects フェーズに登録されることに注意してください。

レイアウト効果を使用する

実際、useEffect を解析してみると、commitMutationEffects ステージと commitLayoutEffects ステージの if 判定では、useLayoutEffect が if で判定されているため、commitMutationEffects ステージでは、前回の useLayoutEffect の破棄関数が同期的に実行され、commitLayoutEffects ステージでは、今回の useLayoutEffect の実行関数が同期的に実行され、破棄関数が登録されることになります。

結論は

ここまで、コミットフェーズのコードをざっと確認し、useEffect が非同期で実行され、useLayoutEffect が同期で実行される理由を分析してきました。これらはすべて変数であるため、記事にはあまり具体的なコードを掲載していません。実際のプロセスの概要と、このメカニズムを設計した React チームのメンタルモデルは、コードの継続的なデバッグと理解を通じて徐々に慣れていく必要があります。

後で興味があるのはフックの実装です。その中でも、より重要な useReducer のソース コードに焦点を当てて、シンプルなバージョンを書いて Alipay アプレットに組み込み、日常の生産性開発のためのカスタム Alipay フックを実装できるかどうかを確認します。

React の useEffect と useLayoutEffect の違いについての記事はこれで終わりです。React useEffect useLayoutEffect に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • ReactのuseEffectクロージャの落とし穴についての簡単な説明
  • React useEffect の理解と使用

<<:  Mysql 8.0.17 winx64バージョンのインストール中に発生した問題を解決する

>>:  MySQL 8.0.17 のインストールと使用方法のチュートリアル図

推薦する

MySQL のデッドロックとデータベースおよびテーブル シャーディングの問題の詳細な説明

MySQL 運用上の問題点を記録します。ビジネスシナリオと問題の説明外部インターフェースをリクエスト...

HTML ブロックレベルタグとインラインタグの違い

1. ブロックレベル要素: 独立して存在できる能力を指します。通常、ブロックレベル要素は改行によって...

SQL Server の完全バックアップに関する珍しいエラーと解決策

1. エラーの詳細一度、データベース全体のバックアップを手動で実行したときに、次のエラーが発生しまし...

Mysql5.7 以降での ONLY_FULL_GROUP_BY エラーの解決方法

最近、開発プロセス中に、プロジェクト開発環境に接続されている MySQL データベースは Aliba...

404エラーページを作成する際に注意すべき問題の簡単な分析

ウェブサイトを最適化するときは、エラー ページの使い方を学ぶ必要があります。たとえば、ウェブサイトに...

ElementUIカスタムCSSスタイルが有効にならない問題を解決する

例えば、入力ボックスがあります <el-入力 ref="mySearch"...

条件によるMysqlカウントの複数の実装方法を詳細に解説

最近、あるウェブサイトのバックエンドに一連の統計機能を追加していたのですが、条件によるカウントが必要...

Flask アプリケーションの Docker デプロイ実装手順

1. 目的Flask アプリケーションをローカルで作成し、Docker でパッケージ化し、独自のサー...

マウスオーバーボタンアニメーションを実現する純粋な CSS3 パート 2

前の 2 つの章を終えて、ボタンのフローティング アニメーションについて新たな理解が得られましたか?...

Linux で Oracle データベースをバックアップするためのスケジュールされたタスクの設定に関するチュートリアル

1. データベースの文字セットを確認するデータベースの文字セットは、Linux で設定された環境変数...

EclipseのプロジェクトをTomcatに追加できない問題を解決する方法

1. プロジェクトを右クリックしてプロパティを選択します2. プロジェクトファセットをクリック3. ...

Navicat でストアド プロシージャ、トリガーを作成し、カーソルを使用する簡単な例 (画像とテキスト)

1. テーブルを作成する<br /> まず、2 つのテーブル (users テーブルと...

MySQL コマンドラインでよく使われる 18 個のコマンド

日常的なウェブサイトの保守と管理では、多くの SQL ステートメントが使用されます。熟練して使用する...

Node.js における npx コマンドの使用法とシナリオ分析

npx 使用チュートリアル今晩、 Vue-Cli勉強していたところ、ふと最新の@4.xxバージョンを...

よく知られているブラウザのDOCTYPEモード選択メカニズム

ドキュメントの範囲この記事では、Firefox やその他の Gecko ベースのブラウザ、Safar...