Reactにおけるキーの役割の詳細な説明

Reactにおけるキーの役割の詳細な説明

React におけるキーの役割を理解するには、まずキーの値から始めます。キーの値は、不定値、インデックス値、明確で一意の値の 3 種類に分けられます。

次のコードでは、キーの値は不定値です(Math.random())

質問: ボタンをクリックすると、スパンの色が赤に変わりますか?

React をインポートし、{useState} を 'react' から取得します。

関数App() {
  定数[initMap、setInitMap] = useState([1,2,3,4]);
  const ハンドルクリック = () => {
    setInitMap([1,2,3,4])
    var spanEle = document.getElementsByTagName('span');
    Array.from(spanEle).map(it => it.style.color = 'red')
  }
  
  戻る (
    <div className="アプリ" id="アプリ">
      {
        initMap.map((it,index) => <div key={Math.random()}><span>色</span></div>)
      }
      <ボタンのonClick={() => handleClick()}></ボタン>
    </div>
  );
}

デフォルトのアプリをエクスポートします。

答えは「いいえ」です

この問題は、Reactレンダリングメカニズムとdiffアルゴリズムに関係しています。

公式ウェブサイトでは、diff に関して次のようなルールが定められています。

  • 要素タイプが変更されると、破棄されて再構築されます
  • 要素タイプが変更されていない場合は、属性を比較します
  • コンポーネント要素の型が変更されていない場合は、propsを通じて子ノードを再帰的に決定します。
  • 子ノードを再帰的に比較します。子ノードがリストの場合は、キーとプロパティで判断します。キーが一貫している場合は更新し、キーが一貫していない場合は破棄して再構築します。

上記の問題を分析します。

ボタンをクリックするとsetInitMap([1,2,3,4])によりレンダリングが発生します。レンダリング時に新しい仮想DOMが生成されます。ただし、この時に取得するspan要素は前の要素であるため(setInitMapは非同期で実行されるため)、新旧DOMの比較が行われます。

コード initMap.map((it,index) => <div key={Math.random()}><span>color</span></div>)

ここでの div はリストです。4 番目の diff ルールと比較して、React はキーに基づいて実際の DOM を更新するかどうかを決定します。 key={Math.random()}の場合、新旧のDOMの値が一致しない場合は、divが再生成されます。更新前に要素に赤いスタイルを追加したので、再作成された要素にはこのスタイルは適用されません。効果は次のようになります。

2番目のケース: キー値がインデックス値である

上記の分析の結果、キーの変更により、レンダリング時に div 要素が再生成されることがわかりました。レンダリングの前後でキーが変更されない場合はどうなるでしょうか?たとえば、キーをインデックスに変更する

質問: このコードでボタンをクリックすると、スパンの色は変わりますか?

戻る (
    <div className="アプリ" id="アプリ">
      <スピン 回転 = {スピン}></スピン>
      {
        initMap.map((it,index) => <div key={index}><span>色</span></div>)
      }
      <ボタンのonClick={() => handleClick()}></ボタン>
    </div>
  );

回答: はい

分析: レンダリングの前後でインデックスが変更されないため、div は再生成されません。次に、span 要素を比較します。span 要素の属性はレンダリングの前後で変更されるため、React は span 要素に新しい属性のみを適用しますが、それらは依然として前の要素を指します。

3 番目のケース: キー値が決定され、一意です。

この例では、キーをindexに設定することで、spanの色が変わりますが、キーを使用する場合、React公式サイトではindexの使用は推奨されていません。

上記のコードを修正する

  定数[initMap、setInitMap] = useState([1,2,3,4]);
  const ハンドルクリック = () => {
    初期化マップを設定します([3,2,1,4])
  }
  戻る (
    <div className="アプリ" id="アプリ">
      {
        initMap.map((it,index) => <div key={index}><input type="radio" />{it}</div>)
      }
      <button onClick={() => handleClick()}>クリック</button>
    </div>
  );
}

初期化時に値3のボタンを選択します

ボタンをクリックしてください

期待される効果は、値が 3 のボタンがまだ選択されているが、値が 1 のボタンになることです。

分析:

  1. setStateはレンダリングを引き起こします
  2. divのインデックスは変更されないため、divは再生成されず、入力は状態とpropsによって制御されないため、要素の状態は変更されません。
  3. 唯一変わるのは、状態によって影響を受けることです

望ましい効果を達成したい場合は、ユニークで確実なキーを設定する必要があります

テスト1:

{
   initMap.map((it) => <div キー = {it}><input タイプ = "radio" />{it}</div>)
}

初期化中に3番目のボタンを選択します

ボタンをクリックしてください

これは期待される効果です

考えてみてください。キーを Math.random() に設定するとどのような効果があるでしょうか?ボタンの状態は保存されますか?

クリックする前に:

クリック後:

無線状態は保存されません。

上記の例を通して、Reactにおけるキーの役割を理解できたと思います。以下の内容はReactの知識ポイントの拡張です。

拡張コンテンツ: 記事の冒頭のコードには、React の他の 2 つの知識ポイントも含まれています。1 つは前述の React のレンダリング条件であり、もう 1 つは実際の DOM の操作です。

拡張1: Reactレンダリング条件

'./App.css' をインポートします。
React をインポートし、{useState} を 'react' から取得します。

関数App() {
  定数[initMap、setInitMap] = useState([1,2,3,4]);
  const [spin, setSpin] = useState(false);
  const ハンドルクリック = () => {
    setSpin(true); //変更された部分 var spanEle = document.getElementsByTagName('span');
    Array.from(spanEle).map(it => it.style.color = 'red')
    setSpin(false); //パーツを変更}
  
  戻る (
    <div className="アプリ" id="アプリ">
      <スピン 回転 = {スピン}></スピン>
      {
        initMap.map((it,index) => <div key={Math.random()}><span>{it}</span></div>)
      }
      <ボタンのonClick={() => handleClick()}></ボタン>
    </div>
  );
}

デフォルトのアプリをエクスポートします。

クリック前のテスト結果は次のとおりです。

クリック後:

このコードでは、div のキーは引き続き Math.random() を使用していますが、initMap の状態は変更されていないため、再レンダリングされません。このとき、div は破棄されずに再構築されます。

拡張 2: 実際の DOM を操作することは可能ですか?

React では、実際の DOM 要素はより複雑なオブジェクトであり、操作には多くの計算が必要になるため、仮想 DOM の登場により実際の DOM に対する操作が削減されます。上記のコードでは、DOM ノードを直接操作してスタイルを変更していますが、これはお勧めできません。 React は状態とプロパティの変更に基づいてページをレンダリングするため、状態を通じてページのレンダリングを制御する方が適切です。

変更されたコードは次のとおりです。

関数App() {
  定数[initMap、setInitMap] = useState([1,2,3,4]);
  const [spin, setSpin] = useState(false);
  const [showColor, setShowColor] = useState(false);
  const ハンドルクリック = () => {
    setInitMap([3,2,1,4]);
    ShowColor を true に設定します。
  }
  
  戻る (
    <div className="アプリ" id="アプリ">
      <スピンスピン={スピン}>
      {
        initMap.map((it,index) => <div key={Math.random()}><span className={showColor && 'span-color'}>色</span></div>)
      }
      </スピン>
      <button onClick={() => handleClick()}>クリック</button>
    </div>
  );
}

このとき、spanは制御されたコンポーネントであり、要素のレンダリングはshowColorの状態によって制御できます。

クリックする前に:

クリック後:

状態を使用してレンダリングを制御すると、コードの量が削減され、結果が期待どおりになります。

要約する

  1. キーを使用する場合は、キーが一意かつ決定論的であることを確認してください。キー値が Math.random() の場合、コンポーネントが再構築され、要素に対する以前の操作が無効になる可能性があります。
  2. ページをレンダリングするときは、実際のDOMを操作せず、状態を使用してページを更新するようにしてください。

以上がReactにおけるキーの役割についての詳しい説明です。Reactキーの役割についてさらに詳しく知りたい方は、123WORDPRESS.COMの他の関連記事もぜひご覧ください!

以下もご興味があるかもしれません:
  • React Native が「NSArray<id<RCTBridgeModule>>型のパラメータを初期化できません」というエラーを報告する (解決方法)
  • Reactの基本のまとめ
  • Reactの親コンポーネントと子コンポーネント間のデータ転送の詳細な説明
  • React 入門レベルの詳細なメモ

<<:  nginx プロキシ サーバーで双方向証明書検証を構成する方法

>>:  Nginx の add_header ディレクティブに注意する必要があるのはなぜですか?

推薦する

seata docker 高可用性デプロイメントの詳細な紹介

バージョン1.4.2公式ドキュメントドッカーハブ起動する環境変数SEATA_CONFIG_NAMEを...

MySQLインスタンスクラッシュ事例の詳細な分析

[問題の説明]私たちの実稼働環境には、複数の MySQL サーバー (MySQL 5.6.21) の...

RocketMQ の Docker インストールとインストール中に発生した問題の解決策

目次rocketmqイメージを取得する名前rvを作成する単一のブローカーノードを作成するrocket...

Centos8 で yum を使用して rabbitmq をインストールするチュートリアル

/etc/yum.repos.d/フォルダに入るrabbitmq-erlang.repo ファイルを...

Linux centos7 環境での MySQL インストール チュートリアル

Linux centos7 環境に MySQL をインストールする手順の詳細な紹介MySQLをインス...

CSS の border 属性と display 属性の使い方の簡単な分析

境界プロパティの概要borderプロパティは要素の境界を設定します。境界線の3要素は、太さ、線の種類...

jsでライトスイッチの効果を実現

この記事の例では、ライトスイッチ効果を実現するためのjsの具体的なコードを参考までに共有しています。...

1 時間で MySQL データベースを学ぶ (Zhang Guo)

目次1. データベースの概要1.1 開発の歴史2. MySQL の紹介2.1. MySQLの概要2....

2048 ゲームを実装するためのネイティブ js

2048ミニゲーム、参考までに具体的な内容は以下のとおりですまず、2048ゲームは16のグリッドか...

Linux デスクトップ用の 4 つのスキャン ツール

ペーパーレスの世界はまだ到来していませんが、書類や写真をスキャンすることで紙をなくす人が増えています...

高度なクローラー - JS 自動レンダリングのための Scrapy_splash コンポーネントの使用

目次1. scrapy_splash とは何ですか? 2. scrapy_splashの役割3. s...

HTML フォーム タグの使用方法を学ぶチュートリアル

HTML のフォームを使用して、ユーザーからさまざまな種類の入力情報を収集できます。フォームは、実際...

MySQL 5.7.31 64 ビット無料インストール版チュートリアル図

1. ダウンロードダウンロードアドレス: https://dev.mysql.com/get/Dow...

本をめくる効果を実現するネイティブJS

この記事では、ネイティブ JS で実装された本をめくる効果の図を紹介します。効果は次のとおりです。 ...

Dockerのデフォルトネットワークセグメントの正しい変更手順

背景同僚がセキュリティ プロジェクトに取り組んでおり、AWS サーバーに秘密兵器を展開する必要があり...