[前回] Django+Reactで学ぶプログラミング基礎(22): Reactチュートリアル(stateを親コンポーネントで管理)
はじめに
前回は、親コンポーネントから子コンポーネントの状態を制御しました。
今回は、イミュータビリティ(不変性)と関数コンポーネントです。
今回の内容
- ゲームを完成させる
- イミュータビリティ(immutability; 不変性)とその重要性
- 関数コンポーネント
イミュータビリティとその重要性
イミュータブルなオブジェクトとは
-
イミュータブル(immutable)なオブジェクトとは
- 作成後にその状態を変えることのできないオブジェクト
- 対義語はミュータブル(mutable)なオブジェクト
- 作成後も状態を変えることができる
- 対義語はミュータブル(mutable)なオブジェクト
- 作成後にその状態を変えることのできないオブジェクト
-
イミュータブルなオブジェクトを使うメリット/デメリット
- メリット
- 複製や比較のための操作を省けるため、コードが単純になる
- 性能の改善につながる
- デメリット
- オブジェクトが変更可能なデータを多く持つ場合
- イミュータブル化は不適切となる場合がある
- オブジェクトが変更可能なデータを多く持つ場合
- よって、イミュータブルかミュータブルか選択できるようにしている
- メリット
変化するデータに対する2種類のアプローチ
- アプローチ1: ミューテートを伴うデータの変化
- データの値を直接変更し、データをミューテート(mutate; 書き換え)する
var player = {score: 1, name: 'Jeff'};
player.score = 2;
// 変更後のplayerは {score: 2, name: 'Jeff'}
- アプローチ2: ミューテートを伴わないデータの変化(イミュータビリティ)
- データの値を変更せず、データのコピーに変更を加え、元のデータを置き換える
var player = {score: 1, name: 'Jeff'};
var newPlayer = Object.assign({}, player, {score: 2});
// playerはそのままで、新しくnewPlayerがコピーされる: {score: 2, name: 'Jeff'}
// スプレッド構文(spread syntax)を使用する場合の書き方
// var newPlayer = {...player, score: 2};
- 最終的な結果は同じだが、差異が存在
イミュータビリティ(内部データを書き換えない)メリット
-
複雑な機能が簡単に実装できる
- 複雑な機能の実装が簡単になる
- 例えば、三目並べの着手の履歴を振り返って、以前の着手まで
巻き戻し
たい- 直接的なデータのミューテートを避けることで
- ゲームの以前のヒストリをそのまま保ち、後で再利用可能
- 直接的なデータのミューテートを避けることで
-
変更の検出
- ミュータブル(mutable)なオブジェクトは中身が直接書き換えられる
- よって、変更があったかの検出が困難
- 以前のコピーと比較してオブジェクトツリーの全体を走査する必要あり
- イミュータブルなオブジェクトは中身が変更されないため
- 変更の検出が簡単
- 参照しているイミュータブルなオブジェクトそのものが(中身ではなく)、元のオブジェクトと同じかチェック
- 異なる場合、変更があったと判断
- ミュータブル(mutable)なオブジェクトは中身が直接書き換えられる
-
React再レンダリングタイミングの決定
- Reactで
PureComponent
を構築しやすくなる- イミュータブルなデータは変更があったら簡単に分かる
- コンポーネントをいつ再レンダリングすべきか決定しやい
- イミュータブルなデータは変更があったら簡単に分かる
-
React.PureComponent
とは- Reactのパフォーマンス改善に使用される手法
-
shouldComponentUpdate()
機能を実装している- 比較対象が複合型(配列、オブジェクトなど)の時、等しいか否かの比較に、浅い比較(shallow compare)を使用
- オブジェクト自身(参照)のみチェックし、オブジェクト中の値(value)はチェックしない
- 比較対象が複合型(配列、オブジェクトなど)の時、等しいか否かの比較に、浅い比較(shallow compare)を使用
- Reactで
-
チュートリアルで、イミュータビリティのコード例
-
Board
のhandleClick(i)
関数でconst squares = this.state.squares.slice();
- 現在の
squares
配列を直接変更しないため、.slice()
メソッドを使って配列のコピーを作成している
-
関数コンポーネント
Reactの関数コンポーネント
-
render
メソッドのみで、state
を持たないコンポーネントを、シンプルに書く方法-
React.Component
を継承するクラスを定義する代わりに-
props
を入力として受け取り、表示すべき内容を返すような関数を定義
-
-
- 関数コンポーネントのメリット
- クラスより楽に書ける
Square
クラスを関数に書き換える
-
this.props
を、props
に書き換える -
onClick={() => this.props.onClick()}
を、onClick={props.onClick}
に書き換える(両側のカッコが消える)
src/index.js
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
おわりに
イミュータビリティと関数コンポーネントの概念を勉強しました。
次回も続きます。お楽しみに。