🌊

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 が再利用されるので想定とずれる可能性がある。


アンチパターン

  • 毎レンダーで createRefuseMemo なし)
    → ref が都度変わり、swipe 呼び出しに失敗しやすい

  • 依存配列を [] に固定
    → 枚数が増えても ref が足りず undefined になる


まとめ

  • [cards.length] 依存は「末尾追加/末尾削除」が中心のデッキに相性が良い。
  • 並び替え・途中削除も考慮するなら ID ベースの Map 再利用が安全。
  • 「どの条件で Ref を再生成するか」を設計に合わせて選ぶのがポイント。
    ト。

Discussion