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 ディレクティブに注意する必要があるのはなぜですか?

推薦する

Webpack プロジェクトでローダー プラグインをデバッグする方法

最近、webpackの使い方を学んでいたときに、webpack-replace-loaderの設定正...

HTMLページ内の検索機能を完了する

最近、たくさんの人に改変してもらったフレームワークに取り組んでいます。毎日コードを見ていると目が回り...

WeChatアプレットに2048ミニゲームを実装する詳細なプロセス

レンダリング サンプルコード今日は、WeChat アプレットを使用して 2048 ゲームを実装します...

Dockerを使用してプライベートGitLabを構築する2つの方法

最初の方法: docker インストール1. オープンソース版のイメージを取得する2. 対応するデー...

WeChatアプレットのスクロールビューが左右連動効果を実現

WeChatアプレットはスクロールビューを使用して左右のリンクを実現します。参考までに、具体的な内容...

JavaScript イベントの概念の詳細な説明 (静的登録と動的登録の区別)

目次js のイベントイベントタイプ一般的なイベントイベント登録静的および動的登録の例onload 読...

nginx のインストールが完了した後に PHP を解析できない問題の解決方法

目次方法1方法2 nginxをインストールした後、PHPコードを解析できないことがわかりました。解決...

MySQL における in と exists の違いの詳細な説明

1. 事前に準備する便宜上、ここで 2 つのテーブルを作成し、そこにいくつかのデータを追加します。果...

JavaScriptタイマーとボタン効果設定の詳細な説明

タイマー効果: <div> <font id='timeCount'...

MySqlデータベースの基礎知識のまとめ

目次基本的なデータベース操作2) データベースを表示する3) データベースを選択する4) データベー...

MySQL 結合クエリの原則の知識ポイント

MySQL 結合クエリ1. 基本概念2 つのテーブルの各行をペアで水平に接続して、すべての行の結果を...

MySQL の order by ステートメントの最適化方法の詳細な説明

この記事では、ORDER BY文の最適化について学びます。その前に、インデックスの基礎的な理解が必要...

Dockerが正常に起動しない原因と解決策を詳しく解説

1. Docker 起動時の異常なパフォーマンス: 1. ステータスが繰り返し再起動している場合は、...

1つの記事でJavaScriptのクロージャ関数について学ぶ

目次変数のスコープ閉鎖の概念クロージャの使用クロージャのデメリット最後に、クロージャのメリットとデメ...

CentOS7 構成 Alibaba Cloud yum ソースメソッドコード

Centos yumフォルダを開くコマンドcd /etc/yum.repos.d/を入力します。 w...