入門」シリーズ第2回は、クリックしたマス目に「X」印をつけます。9つのマス目のデータやその操作をどこで行い、コンポーネント間でどのようにやり取りするのかがポイントです。データをルートコンポーネントにもたせるマルバツのデータは9マス分まとまっていないと、勝ち負けの判定などの処理ができません。そこで、ルートコンポーネントsrc/components/App.jsにもたせることにしましょう。盤面のコンポーネント(Board)にまとめることもできないではありません。盤面はデータの表示、データとその操作はルートコンポーネントとするのが、わかりやすい切り分けです。データをもって子コンポーネントに渡し、参照させるためには、src/components/App.jsは関数でなくクラスコンポーネントに書き直さなければなりません。クラスコンポーネントは、つぎのようにReact.Componentを継承します。備えなければならないのが、render()メソッドです。関数コンポーネントに定めていたreturn文を、この本体に移します。インスタンスにデータを収める特別なプロパティがstateです。constructor()の中で、オブジェクトのかたちでプロパティにデータを与えて初期化してください(「constructor()」参照)。9マスのデータ(squares)は配列にして、要素は確認用にすべて文字列'X'にしました。*/}<Boardsquares={this.state.squares}/></div>);}}親コンポーネントから属性(squares)のかたちで与えられた値は、関数コンポーネントの引数(props)から参照できます。その値を、さらにバケツリレーで子コンポーネント(Square)に属性として渡しているのがつぎのsrc/components/Board.jsのコードです。これでルートコンポーネントのデータの値が、9つのマス目にそれぞれ示されます(図001)。クリックしたマス目に印をつけるマス目ははじめ空白にし、クリックしたら印をつけるようにしましょう。このときも、データを書き替えるのはルートコンポーネントです。クリックするのはマス目ですから、今度は子から親への逆バケツリレーになります。テンプレートの要素がクリックされたことを捉えるのは、onClickイベントです(「イベント処理」参照)。子コンポーネント(src/components/Square.js)がpropsから参照して呼び出すハンドラ関数(onClick())は、親コンポーネント(src/components/Board.js)が与えます。ような)イベントハンドラを渡すには?」参照)。引数(i)に受け取るのがマス目のインデックスです。プロパティstateは、constructor()呼び出しのあとは直に書き替えることはできず、メソッドsetState()を用いなければなりません。引数はオブジェクトで、変更するプロバティ(squares)に新たな値を与えます。値となる配列は、スプレッド構文...により複製したうえで要素を書き替えました。this.handleClick(i)}/></div>);}}注意すべき点として、イベントハンドラのメソッド(handleClick())がthisを参照する場合は、あらかじめconstructor()の本体でFunction.prototype.bind()によりthisをバインドしておくようにしましよう(「関数をコンポーネントインスタンスにバインドするには?」参照)。これではじめはnullで空白にしたマス目に、クリックするとX印がつきます(図002)。前掲コードでは、変更するプロバティ(squares)に、値の配列はスプレッド構文...で複製してsetState()メソッドにより設定しました。もとのデータを直に書き替えない、これがイミュータビリティ(immutability)です(「イミュータビリティは何故重要なのか」参照)。オブジェクトの中身に直接手を加えると、Reactがいつどのような変更があったのか、検出に手間取ります。新たなデータで上書きすれば、変更がはっきりし、その影響範囲とくに描画の更新も最適化されるのです。イミュータビリティは、機能の実装をシンプルにしたり、バグが見つけやすくなるという利点もあります。書き替えた3つのモジュールは、つぎのコード001にまとめます。CodeSandboxに以下のサンプル001を掲げました。