入門」シリーズ第4回は、新たな機能を加えます。それは、待ったをかけることです。盤面の配置データを履歴でもたせ、何手でもさかのぼれるようにします。ゲームの履歴を残す盤面のXとOの配置データは、9マスの値を要素とする配列にもたせました。ゲームは多くても9手で終わりますから、9要素の配列9個ですべての指し手の履歴が残せるということです。そこで、クラスApp(モジュールsrc/components/App.jsのstate)に定めていた盤面の配置データはつぎのようにオブジェクトにして、それを親配列(history)の要素として収めることにします。すれば、一手ごとに9マスの配置をそれぞれ同じかたちのオブジェクトにして、配列要素に加えられるでしょう。Array(9)}],};}}クラスAppが9コマの配置データを扱うのは、クリックイベントのハンドラ(handleClick())とrender()メソッドです。どちらも、まずstateから親配列(history)を参照し、最後の要素から直近の配置データ(squares)を取り出すかたちにしました。親配列はスプレッド構文...で複製して変数(history)に収めています。02」「データの変更にはイミュータビリティが大切」参照)。squares={this.state.squares}squares={squares}/></div>);}}盤面の配置データの構造をオブジェクトの配列で履歴にしたというだけですから、マルバツゲームの動きはこれまでと変わりません(図001)。今が何手目かをボタンのリストで示す履歴(history)には指し手ごとに履歴データが加わります。そのデータの数だけページに履歴ボタンを加えて、今が何手目かを示しましょう(図001)。render()メソッドがArray.map()メソッドでつくっているのは、ボタン(<button>)を入れ子にした<li>要素の配列(move)です。これをメソッドが返すテンプレートに加えれば、配列要素から取り出されて順に差し込まれます。<li>要素に加えたkeyプロパティについては、04「keyプロパティを定める」に項を改めてご説明しますので、少しお待ちください。className="game-info"><ol>{moves}</ol></div></div>);}}ボタンのonClickハンドラに定めるのは、履歴をさかのぼるメソッド(jumpTo)です。コードに問題がないことを確かめたいときには、メソッドにconsole.log()でも仮置きしてください。盤面の配置をクリックした履歴に戻すonClickハンドラのメソッド(jumpTo())は、盤面の配置をクリックした履歴に戻して表示します。いっても、つぎのようにstateに新たに定めた指し手(stepNumber)の現在値を変えるだけです。render()メソッドが履歴からその回のデータを取り出して盤面を描けば配置は戻ります。これにともなって、handleClick()メソッドにも、手を加えました。Array.slice()メソッドにより、さかのぼった手からあとのデータは除いて、履歴を改めています。[...history[this.state.stepNumber].squares];}}履歴ボタンに示すテキストも、Reactのチュートリアルに合わせて書き替えましょう(図003)。ボタンで履歴がさかのぼれるようになりました。start';});}}図003■ボタンで履歴がさかのぼれる書き上がったモジュールsrc/components/App.jsのスクリプト全体は、つぎのコード001にまとめたとおりです。CodeSandboxに以下のサンプル001を掲げました。keyプロパティを定める前述項02で、履歴(history)の配置データから複数差し込む<li>要素にはkeyプロパティを与えました。このプロパティが加えられていないと、Reactの開発時にはつぎのような警告が示されます。prop.配列から動的に要素を加える場合、数が増えたり減ったり、あるいは順番が変わるかもしれません。keyはそのとき、Reactが要素を識別するために求める一意の値です。JavaScriptコードでこの値は参照できませんし、使うこともありません。Reactが内部的に要素をダイナミックに扱えるように与えておくのです(「keyを選ぶ」参照)。して使うことは、項目を並び替えたり挿入/削除する際に問題の原因となります」(「keyを選ぶ」)。一意のkeyは、Reactが要素の動的な変更を追いかけるための仕組みです。問題は配列の途中の要素が除かれたときで、あとの要素のインデックスが繰り上がります。keyが振り直されると、Reactは要素の変更を識別する手段がなくなってしまうのです。今回の作例では履歴をさかのぼってやり直しても、あとのボタンが消えるだけで、すでにある要素のkeyは書き替わりません。Reactのチュートリアルの作例でも、keyの値として配列インデックスが用いられています。「keyが指定されなかった場合、Reactは警告を表示し、デフォルトでkeyとして配列のインデックスを使用します」(「keyを選ぶ」)。「keyはグローバルに一意である必要はありません。コンポーネントとその兄弟の間で一意であれば十分です」(同前)。Appのひな形からチュートリアルと同じマルバツゲームをつくることはできました。ひとつだけ記事を加えます。次回最終回のテーマは、無駄な処理を省く「断捨離」です。