4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Django+Reactで学ぶプログラミング基礎(26): Reactチュートリアル(着手履歴表示とKeyプロパティ)

Last updated at Posted at 2022-06-15
[前回] Django+Reactで学ぶプログラミング基礎(25): Reactチュートリアル(タイムトラベル機能)

はじめに

前回は、タイムトラベル機能を追加しました。
今回は、その続きです。

今回の内容

  • タイムトラベル機能を追加
    • 過去の着手を表示
    • Keyを選ぶ

過去の着手を表示

React要素は第一級JavaScriptオブジェクトで、アプリ内で受け渡し可能

  • 第一級オブジェクトの性質

    • 変数やデータ構造に格納できる
    • 関数のパラメータ(引数)として渡せる
    • 関数の戻り値として返却可能
    • プロパティやメソッドを持つことができる
    • 無名関数(無名リテラル)として表現できる
    • 実行時に動的生成できる
  • Reactで複数要素を描画するには、React要素の配列を使う

    • JavaScript配列のmap()メソッドを用いて、データを別のデータにマッピング可能
const numbers = [1, 2, 3];
const doubled = numbers.map(x => x * 2); // [2, 4, 6]

着手履歴の配列をマッピングし、画面上のボタンを表すReact要素を作成

  • 過去の手番にジャンプするためのボタン一覧を表示
  • Gamerenderメソッド内でhistorymapを適用
    • history配列をループ処理する部分で
      • step変数は、history内の現在の要素を表す
      • move変数は、現在要素のインデックスを表す
src/index.js
  render() {
    const history = this.state.history;
    const current = history[history.length - 1];
    const winner = calculateWinner(current.squares);

    const moves = history.map((step, move) => {
      const desc = move ?
        'Go to move #' + move :
        'Go to game start';
      return (
        <li>
          <button onClick={() => this.jumpTo(move)}>{desc}</button>
        </li>
      );
    });

    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

    return (
      <div className="game">
        <div className="game-board">
          <Board
            squares={current.squares}
            onClick={(i) => this.handleClick(i)}
          />
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
        </div>
      </div>
    );
  }

着手履歴に該当するボタン<button>を持つリストアイテム<li>を作成

  • ボタンにはonClickハンドラが存在

    • this.jumpTo()というメソッドを呼び出す(実装は後で)
    • これにより、ゲーム内で行われた着手のリストが表示される
  • VS Codeでアプリをデバッグ起動(F5)し、ブラウザで確認
    image.png

keyを選ぶ

  • ブラウザで、デベロッパーツール(F12で起動)のコンソールに出力される警告に着目

    • Warning: Each child in an array or iterator should have a unique “key” prop. Check the render method of “Game”.
      image.png
  • keyは配列またはイテレータの特別なプロパティで、Reactによって予約される

    • Reactが、どの要素が変更/追加/削除されたかを識別する際、自動的に使用される
    • 配列内の項目を正しく識別するため、それぞれの項目にkeyを与えるべき
    • keythis.props.keyのような形では、参照できない
    • コンポーネントが自身のkeyを確認する方法はない
  • 動的リストを構築する場合、正しいkeyを割り当てることが強く推奨される

    • 適切なkeyがない場合、データ構造を再構成し、keyを付与すべき
  • keyが指定されなかった場合、Reactは警告を表示する

    • デフォルトのkeyとして、配列のインデックスが使用される
    • 配列のインデックスをkeyとして用いることは、トラブルの元
      • 項目の並び替え/挿入/削除などの操作で問題が発生する
    • 明示的にkey={i}を渡すことで、警告を消すことはできるが
      • 配列のインデックスを使う場合と同様、問題が生じるため推奨されない
  • keyはグローバルに一意である必要はない

    • コンポーネントとその兄弟間で一意であれば十分
  • リストをレンダリングする際、各リスト項目にkey情報を持たせるべき

    • リストが変更された場合、Reactがどのアイテムが変更されたか把握できる
    • リストアイテムに対する、追加/削除/並び替え/中身書き換え、などの操作で
      • リストの各項目にkeyプロパティを与えることで、兄弟要素と区別できる
<li key={user.id}>{user.name}: {user.taskCount} tasks left</li>
  • keyを用いた、リストの再レンダリング

    • Reactは新リスト項目のkeyに対し、旧リスト項目内に同じkeyを持つものが存在しないか探す
      • 旧リストに存在しなかったkeyが、新リストに含まれている場合
        • Reactはコンポーネントを新規作成
      • 旧リストに存在したいずれのkeyも、新リストに含まれていない場合
        • Reactは以前のコンポーネントを破棄
      • 2つのkeyがマッチした場合
        • 該当コンポーネントは移動される
  • keyは、Reactにコンポーネントの同一性に関する情報を与える

    • よって、Reactが再レンダリングされても、stateを保持できる
    • コンポーネントのkeyが変わった場合
      • コンポーネントは破棄され、新しいstateで再作成される

おわりに

着手履歴の画面表示とKeyプロパティを勉強しました。
次回も続きます。お楽しみに。

[次回] Django+Reactで学ぶプログラミング基礎(27): Reactチュートリアル(タイムトラベル実装とチュートリアルまとめ)
4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?