前提
HTML/CSSは仕事で使っておりJSは試行錯誤して触りながら動かしている程度の人間です。
まずJSをもっと勉強してからReactしろって話はおいておいて。
React.jsの公式ドキュメントにある三目並べをやっているのですが、理解できずに躓いた部分のメモです。まったくもって解説とかではなく、躓いた部分について振り返りながら「なるほど。こういうことか」と思っている頭の中を書き連ねており、学習して成長するためにも恥をさらしまくっているだけですのであしからず。しかも思考を書き連ねているので非常に読みづらいですが、自分の頭の中をまとめるものなのでご容赦を。
JSがわかる方にとっては小学生の頭の中を見ているみたいな感じだと思うので温かく見守っていただけると嬉しいです。そして間違っている点はコメントいただけたら泣いて喜びます。
疑問1:state のリフトアップ
「ゲームを完成させる」章のstate のリフトアップ以降から頭に入らない…。これ理解できなくてもReactがどういうものなのかを知るだけなら気にせず先に進んだほうがいいものなんでしょうけど、この段階から理解できなくてそれ以降の話にもついていけなくて頭の中がこんがりはじめたので復習も兼ねて。
ゲームの勝者を決めるためにどの枠が埋まっているのかを把握しなければならないという概要は理解できるのですが、以下の記述の意味が理解しきれない。(書いてたらなんとなくわかってきたので正確には「理解しきれなかった」)
const [squares, setSquares] = useState(Array(9).fill(null));
疑問1:解決
[squares, setSquares]
でsquaresという名前の変数を宣言している。そのデフォルト値として(Array(9).fill(null))
により9個の要素を持つ配列を作成し、それぞれの要素をnullとする。
ここまでは大丈夫。
useState() コールは、state 変数 squares を宣言し、初期値をこの配列にします。
このuseState
ってなんだっけ?
答えは『インタラクティブなコンポーネントの作成』の章にあり。
何かを「記憶」するために、コンポーネントは state というものを使用します。
React は、useState という特別な関数を提供しており、コンポーネントからこれを呼び出すことで「記憶」を行わせることができます。Square の現在の値を state に保存し、Square がクリックされたときにその値を変更しましょう。
つまりsquaresという名前の変数に9個の要素を持つ配列を作成し、それぞれの要素をnull(初期値)を記憶させているということであっているのかな?
そして[squares, setSquares]
は、squares
が state の現在値を格納し、setSquares
はその値を更新するために使う関数を指定している。
これ、setSquares
で関数を指定する意味って何なんだろ?(以降の作業中に解決済)
まぁ取り合えずこれで
[null, null, null, null, null, null, null, null, null]
という配列が作られる。
疑問2:Square がクリックされたときに起こることを変更
function Square({ value, onSquareClick }) { //2
return (
<button className="square" onClick={onSquareClick}> //1
{value}
</button>
);
}
export default function Board() {
const [squares, setSquares] = useState(Array(9).fill(null));
function handleClick() {
const nextSquares = squares.slice();
nextSquares[0] = "X";
setSquares(nextSquares);
} //4
return (
<>
<div className="board-row">
<Square value={squares[0]} onSquareClick={handleClick} /> //3
//...
);
}
この1~4の一連の流れがわからない!
1. buttonをクリックしたときに onClick
で Square
コンポーネントが onSquareClick
という名前の関数を呼び出す。
2. 1で指定した関数 onSquareClick
を Square
コンポーネントの props に追加する。
この props に追加する作業って何…?
propsがいまいちわかっていないのですよね。
propsとは?
ざっとpropsでできることはわかるものの、そもそもpropsって何なの?という疑問が解消されない。
めちゃくちゃわかりやすい記事ありました!
props : 親コンポーネントから子コンポーネントへ値を渡すための仕組み
つまり function Square({ value, onSquareClick }) {
で子であるBoardの onSquareClick
に関するデータを引き抜いてきている?
子から親へ値を渡すことはできない
とあるので親はBoard、子はSquareが正しいのか…?とか思ったのですが、state のリフトアップ の冒頭にこたえが書いてありました。記憶力大丈夫なのかしら?
ゲームの state を各 Square ではなく親の Board コンポーネントに保持させることです。Board コンポーネントは、それぞれの Square に、何を表示するのか props を使って伝えることができます。
そもそも1つ1つの四角 Sqare
のまとまりが Board
なのでした。そんな初歩的なこと忘れる?こうやって疑問点や復習を書き出すとどれだけ理解せずに進めてるかわかっていいですね。
さて、もはや余談になってしまった項目2は解決したので3へ。
3. 2で作った関数 onSquareClick
を onSquareClick={handleClick}
により接続
4. 3で作った関数 handleClick
に内容を定義する。その定義の内容は以下
function handleClick() {
const nextSquares = squares.slice();
nextSquares[0] = "X";
setSquares(nextSquares);
}
nextSquares
という名前の関数を作り、slice() 配列メソッドを使って squares 配列のコピー (nextSquares) を作成。
????????????????
あ、これnextSquaresはsquares配列のコピーを作りますって宣言してるのか。最初からそう言っているんだけど一瞬、何??????????????ってなってしまった。
で、nextSquares[0]
は X と表示され、新しく作成された nextSquares
配列を使って、setSquares
関数を呼び出して状態を更新。これにより、squares
の内容が新しい配列で置き換わる。
ここでやっとstateのリフトアップで記述した setSquares
!
[null, null, null, null, null, null, null, null, null]
これを更新しているのか。
疑問2:解決
一連の流れをまとめると、四角(Square)をクリックしたら「X」が表示され、[null, null, null, null, null, null, null, null, null]が更新される。
こうやって読み解いていくと「説明通りのことしか起こっていないわ」と毎回思うんですが、それに気づくまでが長いんですよね。
そうして、これでは nextSquares[0]
の四角しか「X」にならないので nextSquares[i] = "X";
にしてと続いていく…
勝敗を決める部分は今からなので、また更新するかと思いますがいったんここまで。