React component の Key が 鍵
component と state の関係
コンポーネントにはそれぞれステートが存在する。簡単に下記のようなコードの時、ParentComponent
の中にChildrenComponent
が2つ定義されているので合計3つのステートが存在することになる。
const ParentComponent = () => {
return (
<>
<ChildrenComponent />
<ChildrenComponent />
</>
)
}
当然、それぞれのChildrenComponent
は独立したステートを所有しているので内部でカウントアップするような処理を行ってもそれぞれのステート内部の変数は共有されない。
つまり各コンポーネントのクリック回数は独立してカウントされる。
ではこれにさらに、トグルボタンを用意して2つのChildrenComponent
の表示を片方ずつに限定して切り替えるようにしてみる。トグルによってコンポーネントが切り替えられたことが分かりやすいようにtitle
というプロップスをParentComponent
からChildrenComponent
に渡している。
トグルボタンを押すことでtitle = A
のコンポーネントとtitle = B
のコンポーネントの表示が切り替わるはずだ。
ではいくつかカウントアップをした状態でもう一方のコンポーネントに表示を切り替えると不思議なことに値が切り替わらない。
ReactのコンポーネントのステートはDomの位置に対応してアタッチするコンポーネントを選んでいるため、title = A
のコンポーネントが存在していた箇所にtitle = B
のコンポーネントが置き換わるとステートがリセットされない仕組みになっている。
それを証明するために例えばtitle = A
のコンポーネントにのみdiv
タグで囲んだ上で同じ挙動をさせるとDomの構造が変わるのでステートはリセットされる。
React component の Key が 鍵
上のコードのように敢えてDom構造を変えてステートが共有されないようにするのも良いが書き方的にスマートではない。そこで2つのChildrenComponent
のステートを識別させるために使用するのがKey
プロパティだ。
使い方は簡単でコンポーネントにKey
プロパティと値を設定してあげれば良いだけ。
カウントアップをいくつか行った上でコンポーネントを切り替えると期待通りにステートの値がリセットされている。
(おまけ)コンポーネントをリセットした後も以前の値を維持したい
先ほどのコードでtitle = A
のコンポーネントでいくつかカウントアップをした後にtitle = B
のコンポーネントに切り替えて、再度title = A
のコンポーネントを表示するとカウントが0
になっている。
一度目のレンダリング時にカウントアップした値をtitle = A
のコンポーネントで保持したままにしたい場合、下記のようにParentComponent
の中にtitle = A
のコンポーネントとtitle = B
のコンポーネントのステートを定義して、それぞれ更新していくようにする必要がある。
Discussion