はじめに
Reactで配列からmap
メソッドを使ってJSXでリスト要素を作成したときにkey
をつけ忘れてwarningで怒られてつけるということよくあるのではないでしょうか?
Warning: Each child in a list should have a unique "key" prop.
リスト要素にはkey
を渡そうねとか、そのときmap
のindex
使うのはよくないよ、という記事はよく見かけますが、今回はReactの公式ドキュメントを読んでいてリスト要素以外でもkeyが活かせるパターンを見つけたので紹介します。
こちらの章ではそれuseEffect
使う必要ないんじゃない?という例をいろいろと紹介しているのですが、その中で、渡ってくるprops
が変わるたびにstate
を初期化したい場合はuseEffect
使わずにkey
属性が使えるよ、という話がありました。
NGな例🙅
useEffect
を使って初期化する場合
const Profile = ({ userId }) => {
const [comment, setComment] = useState('');
useEffect(() => {
setComment(''); // userIdが変わるたびにcommentが空文字列になる
}, [userId]);
// ...
}
Goodな例🙆
呼び出し側でkey
にも初期化のトリガーにしたい変数を渡す
const ProfilePage = ({ userId }) => {
return (
<Profile
userId={userId}
key={userId} // これでもuserIdが変わるたびにcommentが空文字列になる
/>
);
}
const Profile = ({ userId }) => {
const [comment, setComment] = useState('');
// ...
}
仕組み
Reactでは同じコンポーネントをReactの仮想DOMツリーの同じ位置に描画する場合、そのコンポーネントのstate
を保持したまま更新します。
しかし、key
属性を追加してuserId
が異なるコンポーネントは異なるkey
になるようにすることで、別のコンポーネントと見なされてDOMを再生成するので、state
もリセットさせることができます。
最後に
key
はリスト要素にしか使ったことがなかったのですが、こんな使い方もあるんですね。
NG例のようなことをしている箇所を見つけたらkey
で代用できないか検討したいと思いました。
ちなみに最初に貼った公式ドキュメントのページの一番最後にReactアプリのプレイグラウンド付きのチャレンジ問題があるのですが、その3問目がちょうどこの例なので、サクッと試してみたい場合はそれを使うとよいかもしれません。