🌊
useMemo で「カード枚数に応じた Ref 配列」を安定化する理由
useMemo で「カード枚数に応じた Ref 配列」を安定化する理由
背景
TinderCard のように 子コンポーネントのメソッド(swipe)を外から叩きたい場合、各カードに ref を割り当てる必要があります。
しかし、毎レンダーで createRef すると ref が再生成されて参照が切れるため、useMemo で「必要なときだけ」作り直すのが大切です。
実装例
// 各カードに個別の ref を作成(枚数が変わる時だけ再生成)
const childRefs = useMemo(
() => cards.map(() => createRef<any>()),
[cards.length]
);
なぜ依存を [cards.length] にするのか
- 依存を
cardsにすると
→ テキスト変更など中身が変わるたびに Ref が再生成され、Imperative Handle が失われる。 - 枚数変化だけを見ると
→ 既存カードの Ref は 同じインデックスで維持され、スワイプ呼び出しが安定する。
注意点
- 配列インデックスに紐づける設計が前提。並び替えや途中挿入があるとズレる。
-
同じ長さで中身が全く別の
cardsに差し替えた場合、Ref が再利用されるので想定とずれる可能性がある。
アンチパターン
-
毎レンダーで createRef(
useMemoなし)
→ ref が都度変わり、swipe 呼び出しに失敗しやすい -
依存配列を
[]に固定
→ 枚数が増えても ref が足りずundefinedになる
まとめ
- [cards.length] 依存は「末尾追加/末尾削除」が中心のデッキに相性が良い。
- 並び替え・途中削除も考慮するなら ID ベースの Map 再利用が安全。
- 「どの条件で Ref を再生成するか」を設計に合わせて選ぶのがポイント。
ト。
Discussion