ReactのPropsの簡単な比較

ReactのPropsの簡単な比較

先週面接に行ったとき、面接官からPureComponentpropsを比較する方法を尋ねられました。その概念はすでに頭に記憶されていたので、私が最初に口走ったのは「浅い比較」でした。その後、面接官から浅い比較のやり方を尋ねられましたが、答えることができませんでした。

週末を利用して、ソース コードでどのように実装されているかを確認してください。

クラスコンポーネントのプロパティ比較

クラス コンポーネントを更新する必要があるかどうかは、shouldComponentUpdate メソッドを実装する必要があります。一般的に、PureComponent を継承する場合は、デフォルトで浅い比較が実装されます。

// ReactBaseClasses.js
関数 ComponentDummy() {}
ComponentDummy.prototype = Component.prototype;

/**
 * sCU のデフォルトの浅い等価性チェックを備えた便利なコンポーネント。
 */
関数 PureComponent(props, context, updater) {
  プロパティ
  this.context = コンテキスト;
  // コンポーネントに文字列参照がある場合は、後で別のオブジェクトを割り当てます。
  this.refs = 空のオブジェクト;
  this.updater = アップデーター || ReactNoopUpdateQueue;
}

ComponentDummy は、コンポーネントのプロトタイプをクラス化して作成します。
pureComponentPrototype.コンストラクタ = PureComponent;
// これらのメソッドの余分なプロトタイプジャンプを回避します。
オブジェクトに pureComponentPrototype を割り当てます。
pureComponentPrototype.isPureReactComponent = true;

PureComponentの実装は上記の通りです。以前はshouldComponentUpdateメソッドを宣言するとデフォルトで実装されると思っていましたが、実はデフォルトメソッドは存在しません。

次に、 shouldComponentUpdateメソッドの呼び出しを見てみましょう。

// ReactFiberClassコンポーネント.js
関数 checkShouldComponentUpdate(
  進行中、
  俳優、
  古いProps、
  新しいプロパティ、
  古い状態、
  新しい状態、
  次のコンテキスト、
){
  const インスタンス = workInProgress.stateNode;
  // インスタンスが shouldComponentUpdate を実装している場合は、それを呼び出した結果を返します。if (typeof instance.shouldComponentUpdate === 'function') {
    const shouldUpdate = instance.shouldComponentUpdate(
      新しいプロパティ、
      新しい状態、
      次のコンテキスト、
    );
    shouldUpdate を返します。
  }

  // PureReactComponent を使用する場合の浅い比較 if (ctor.prototype && ctor.prototype.isPureReactComponent) {
    戻る (
      !shallowEqual(古いプロパティ、新しいプロパティ) || !shallowEqual(古い状態、新しい状態)
    );
  }

  true を返します。
}

実際には PureReactComponent 用に別途 shouldComponentUpdate メソッドが記述されていないことがわかりますが、比較中に浅い比較の結果が返されます。

浅い比較の答えはすべて shallowEqual メソッドにあります。

浅い同等の浅い比較

// 浅いイコール.js
関数 shallowEqual(objA: mixed, objB: mixed): ブール値 {
  // 同じオブジェクトがtrueを返す
  オブジェクトがobjA、objBである場合
    true を返します。
  }

  // オブジェクトまたは null でない場合は false を返します
  もし (
    objA の型 !== 'オブジェクト' ||
    objA === null ||
    objB の型 !== 'オブジェクト' ||
    objB === null
  ){
    false を返します。
  }

  定数 keysA = Object.keys(objA);
  定数 keysB = Object.keys(objB);

  // キーの数が異なる場合はfalseを返す
  (keysAの長さ!==keysBの長さ)の場合{
    false を返します。
  }

  // 対応するキー値が同じでない場合はfalseを返す
  (i = 0 とします; i < keysA.length; i++) {
    もし (
      !hasOwnProperty.call(objB, keysA[i]) ||
      !Object.is(objA[keysA[i]], objB[keysA[i]])
    ){
      false を返します。
    }
  }

  true を返します。
}

shallowEqualメソッドの原理は非常にシンプルです

  1. まず、2 つが同じオブジェクトであるかどうかを判断します。
  2. 両方の値がオブジェクトではないか、または null であるかを判断します。
  3. 2 つのキーの長さを比較します。
  4. 2つのキーに対応する値が同じかどうかを判断します。

原理は、とても単純な比較だということがわかりました。面接中にソースコードを暗唱できれば、給料は上がるのでしょうか?

機能コンポーネントの簡単な比較

関数コンポーネントの浅い比較メソッドは、React.memo メソッドを使用して実装されます。

// ReactMemo.js
関数メモ<Props>をエクスポートします(
  タイプ: React$ElementType、
  比較しますか?: (oldProps: Props, newProps: Props) => ブール値、
){
  定数要素タイプ = {
    $$typeof: REACT_MEMO_TYPE、
    タイプ、
    比較: 比較 === 未定義? null: 比較、
  };
  要素タイプを返します。
}

React.memo メソッドは、2 番目のパラメータとして比較関数を渡すこともサポートしています。

内部処理では、実際には、後続の型判断を容易にするために、$$typeof を REACT_MEMO_TYPE として手動で ReactElement を作成します。

React.memo コンポーネントの作成はもう少し複雑です。2 番目のカスタム比較関数を渡すことができるため、実際には内部的に 2 種類の Fiber ノードとして定義されます。

  • 比較関数が渡されないものは SimpleMemoComponent です。
  • カスタム比較関数に渡すのは MemoComponent です。

ただし、Props の実際の比較は同じであり、比較にはデフォルトで shallowEqual メソッドが呼び出されます。

シンプルメモコンポーネントの更新

もし (
  shallowEqual(前のプロパティ、次のプロパティ) &&
  現在の参照 === 進行中の参照
){
	// ...
}

メモコンポーネントの更新

// ...
compare = Component.compare; とします。
compare = compare !== null ? compare : shallowEqual;
if (比較(prevProps, nextProps) && current.ref === workInProgress.ref) {
  bailoutOnAlreadyFinishedWork(current、workInProgress、renderLanes) を返します。
}
// ... 

なぜ2つに分かれているのかはよく分かりませんが、おそらくアップデートのスケジュールに関係しているのでしょう。

SimpleMemoComponent の Fiber ノードは、実際には名前が変更された関数コンポーネントに相当します。プロセスは関数コンポーネントに直接進みますが、MemoComponent はシェルで覆われています。まずシェルを剥がして子 Fiber ノードを生成し、子 Fiber ノードの判断に基づいて関数コンポーネントに進む必要があります。

上記はPropsの簡単な分析です。

以上がReactにおけるPropsの浅い比較の詳細な内容です。ReactにおけるPropsの浅い比較の詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • Reactのコンテキストとプロパティの説明
  • Reactの3つの主要属性におけるpropsの使用の詳細な説明
  • ReactのRender Propsパターンについて話す
  • ES6 クラスチェーン継承、インスタンス化、React Super (props) 原則の詳細な説明
  • React Propsの原理を理解するのに役立つ記事

<<:  MySQL 5.7を完全にアンインストールするための詳細な手順

>>:  Centos サーバーで nginx を設定する方法の例

推薦する

ReactにおけるRefの相互利用の詳細な説明

目次1. まずRefとは何かを説明しましょう2. フックでのrefの使用1. HTMLDomフックで...

MySQL 外部キー制約の詳細な説明

公式ドキュメント: https://dev.mysql.com/doc/refman/5.7/en/...

WeChatアプレットでのwxsファイルの素晴らしい使い方をいくつか紹介します

目次序文応用フィルタードラッグファイル間での参照の受け渡しwxsはjsロジック層にパラメータを渡しま...

ウェブデザインの達人がよく使うレスポンシブフレームワークを共有する(要約)

この記事では、Web デザインの達人がよく使用するレスポンシブ フレームワーク (概要) を紹介し、...

ウェブサイトにダークモード切り替え機能を持たせるための純粋なCSSフリー実装コード

序文ダーク モードの概念は、 MacOS系統のMojaveに由来し、ユーザーが選択できる 2 つのス...

nginx は画像表示の遅さとダウンロードの不完全さの問題を解決します

前面に書かれた最近、ある読者から、ブラウザからサーバーにアクセスすると、画像の表示が遅く、ブラウザに...

CentOS SVN サーバーで複数のプロジェクトを管理する方法

一つの要求一般的に、企業には複数のプロジェクトがあります。SVN サーバーを設定した後は、プロジェク...

MySQL 最適化における B ツリー インデックスの知識ポイントのまとめ

SQL を最適化する必要があるのはなぜですか?当然ですが、SQL ステートメントを記述する場合、次の...

アリババの中秋節ロゴとウェブサイトのデザインプロセス

<br />まずアイデアを考え、次にスケッチを描き、次にマウスでスケッチし、最後にフラッ...

mysql 更新ケース更新フィールド値が固定されていない操作

特定のデータの一括更新処理において、特定のステータスが固定値に更新されるなど、更新するフィールドの値...

MySQL の主キーとトランザクションの詳細な説明

目次1. MySQLの主キーとテーブルフィールドに関するコメント1. 主キーと自動増分2. テーブル...

PID を作成できないために MySQL が起動できない問題を解決する方法

問題の説明MySQL 起動エラー メッセージは次のとおりです。 mysqld を起動します (sys...

Linux における「/」と「~」の違いの詳細な説明

「/」はルートディレクトリ、「~」はホームディレクトリです。 Linux ストレージはツリー状にマウ...

MySQL の frm ファイルからテーブル構造を復元する 3 つの方法 [推奨]

mysql が正常に実行されている場合、テーブル構造を表示することは難しくありません。しかし、場合...

Alibaba Cloud Centos7.X で外部にポートを開く方法

一言で言えば、大手メーカーからクラウド サーバーを購入する場合は、セキュリティ グループに移動して、...