React:三目並べ(コンポーネント、props、handleClick、state )
- classNameを使ってスタイルをあてることができる
- Reactコンポーネントを表示することができる
- 親コンポーネントから子コンポーネントに値を渡すことができる(props)
- インタラクティブなコンポーネントが作成できる(=クリック時に反応させるhandleClick)
値を渡すprops
親コンポーネントから子コンポーネントに値を渡す。今回はvalueという引数名を使用。
子コンポーネント
before
function Square() {
return <button className="square">1</button>
}
after
function Square({value}) {
return <button className="square">{value}</button>
}
親コンポーネント
before
<Square/>
<Square/>
<Square/>
after
<Square value="1" />
<Square value="2" />
<Square value="3" />
クリック時に反応させるhandleClick
子コンポーネントに記載。これで、ボタンをクリックするとログが出力されるようになる。
before
function Square({value}) {
return <button className="square">{value}</button>
}
after
function Square({value}) {
function handleClick() {
console.log('クリック');
}
return <button className="square" onClick={handleClick}>{value}</button>
}
コンポーネントに記憶させるstate
- useStateをインポート
- state変数(現在の状態valueと更新用の関数setValue)、初期値useState(null)を設定
- イベントハンドラ関数handleClickに、クリック時の動作を記述
import { useState } from "react";
function Square() {
const [value, setValue] = useState(null);
function handleClick() {
setValue('X');
}
return <button className="square" onClick={handleClick}>{value}</button>
}
親コンポーネントはこの状態に戻す。
<Square/>
<Square/>
<Square/>
今の状態では、四角をクリックするとXが増えていくだけ。
親にstate管理をさせる
「state の親コンポーネントへのリフトアップ(持ち上げ)」と言う。
- 複数の子コンポーネントからデータを収集したい
- あるいは 2 つの子コンポーネント同士で通信したい
と言う時は、親コンポーネントにstateを宣言する。handleClickも持たせる。
const [squares, setSquares] = useState(Array(9).fill(null));
function handleClick(i) {
const nextSquares = squares.slice();
console.log('nextSquares', nextSquares);
nextSquares[i] = "X";
setSquares(nextSquares);
}
Array(9).fill(null)
は、9 個の要素を持つ配列を作成し、それぞれの要素をnull
に設定します。それを囲むuseState()
コールは、state 変数squares
を宣言し、初期値をこの配列にします。配列の各要素は、個々のマス目の値に対応します。後で盤面が埋まってくると、squares
配列は次のような見た目になる予定です:['O', null, 'X', 'X', 'X', 'O', 'O', null, null]
<Square value={squares[0]} onSquareClick={() => handleClick(0)}/>
<Square value={squares[1]} onSquareClick={() => handleClick(1)}/>
<Square value={squares[2]} onSquareClick={() => handleClick(2)}/>
◾︎アロー関数について
ユーザがクリックするまで
handleClick
を呼び出したくないので、handleClick(0)
を呼び出す関数がほしい。
新しい() =>
構文に注目してください。この() => handleClick(0)
はアロー関数と呼ばれる、関数を短く定義する方法です。マス目がクリックされると、アロー (=>
) の後のコードが実行され、handleClick(0)
が呼び出されます。
子コンポーネントはこれだけになる。
function Square({value, onSquareClick}) {
return (
<button className="square" onClick={onSquareClick}>
{value}
</button>
);
}
- ボタンを押すと、親から子へ管理番号(value)とイベント実行の権利(onSquareClick)が渡され、子はイベントを発火する。イベント内容(
handleClick
)は親コンポーネント内に記述されている。 - 【親】
handleClick
は管理番号を使って、squares
配列の要素をnull
からX
に更新する。(更新関数を使用) - 【親】状態stateが更新されたので、親と子が全て再レンダーされる。これで、valueがnullからXになる。
イミュータビリティ(不変性、直接更新しないこと)の大切さ
handleClick
内で既存の squares
配列を直接変更するのではなく、.slice()
を使ってコピーを作成していたのはイミュータビリティの保持のため。
元のデータの書き換えを行わないことで、いくつかの利点を得ることができる。
- 操作の履歴を見たり、操作を巻き戻す機能が実装できる。
- コンポーネントのデータが変更されたかどうかを比較できる → 再レンダー不要な子コンポーネントを識別し、レンダーさせない。