初投稿です!どうせならアウトプットしたいなー程度で作りました。
今回作るアプリ
今回作るのは「三目並べ」というゲームです。
Reactの公式チュートリアルにおいてあるものです。
自分は今回初めてReactを触るので大まかな特徴と自分がつまずいた部分のみ語ろうと思います。
Reactの特徴
まず、Reactの機能の一つとしてコンポーネントがあります(以下引用)
-コンポーネント(公式ドキュメントより)
React では、コンポーネントとは UI の部品を表す再利用可能なコードのことです。コンポーネントは、アプリケーションの UI 要素を表示し、管理し、更新するために使用します。
表示したいものをhtml,javascript,まとめて一つの部品として管理できるものって感じ。
コンポーネントの内部にコンポーネントを呼び出したり、コンポーネント同士での変数やStateを呼び出したりして複雑な処理がかけそう。(小並感)
他のファイルから作成したコンポーネントをインポートすることも可能。
これは自分用なんですが、コンポーネント内で複数のタグ(JSX要素)を使いたいときはフラグメント(<> および >)で囲む必要があります。
UseState
クリックしたときの処理をhandleClickとして定義するところからuseStateを用いています。
あまり詳しい理解ではないですが自分の解釈を...
const [value, setValue] = useState(null);
このように記述し、setValueでvalueを更新する形です。
Board内のSquareはそれぞれ独自のStateを保持しているため、コンポーネントごとに更新されるそうです。
state の親コンポーネントへのリフトアップ(持ち上げ)は値を親コンポーネントでまとめて管理するためにするそうです。おそらく、コンポーネント内部で定義したstateを外にだせないからかなと自分は解釈してます。
再レンダリング
クリックした際、状態を管理する変数stateがBoardにあり、Squareから直接この変数を変更することはできません。その為、BoredからSquareに関数を渡して、クリック時にSquareから関数を呼び出しています。
関数handleClick内の処理では、簡単に言うとsquares配列をコピーしてi番目のみ変更する感じです。
しかし、以下の書き方ではうまくいきません。
<Square value={squares[0]} onSquareClick={handleClick(0)} />
これは、handleClickの呼び出しがBoardのレンダーの一部として発生するからだそう。
handleClickの処理で、setSquaresが呼び出されてstateが更新されますが、この時にBoard全体が再レンダリングされ再びhandleClickが呼び出されるという無限ループに陥るためです。
これを解決するには、さらに別の関数を定義してその中でhandleClickを呼び出せばいいですが煩雑です。
代わりにクリック時に呼び出される関数をアロー関数で定義します。
この問題はクリック時に関数の呼び出しを行ってしまうことが原因でした。なので、アロー関数でプロパティとして設定することで、再レンダリングしてもクリックするまで実行されないので無限ループから抜け出すことができます。
イミュータビリティ
handleClick内でなぜsquires配列をわざわざコピーして変更していたかはimmutabilityにあります。
データを変更する方法は二種類あり、
・データを直接書き換え(ミューテート)
・臨んだ変更をしたコピーで元のデータを置換する
です
後者を選ぶことで以下の利点が得られます。
・過去のデータを保持でき、後で再利用したり巻き戻し機能を加えることができる。
・必要な箇所のみの再レンダリングを行いたいときにデータの変更の有無が比較しやすい。
今回のは後者
最後に
今回割と小さいゲームのみだったのでWEBでも作って解像度上げたいですね。
ReactはカスタムフックとかuseEffectとかまだ何も知らないので早く使いたいです。
さらっと調べてuseStateと再レンダリングはなにやら関係性があるらしいので、
別の記事で自分の解釈残すかもです。