2025年5月14日

drawerを開けたらチェックがついている年月にスクロール

過去に、イベント発火したら、特定のスクロール箇所が表示される要件があった。 スムーズにスクロールするのではなく、瞬時に表示したかった。 その時は、refを使ってスクロール箇所を特定して、表示できるようにした。 その時に、refだけを用いて、特定の高さだけ下に移動する処理にした。 困難だったのは、drawerを開いてもrefがnullのままだったため、scrollIntoViewが発火せずに何も起こらなかった。 そのため、必要なUIとrefを子コンポーネントに切り出す事でrefがnullでは無くなったので解決した。

今回は、Drawerを開く際に、スクロール処理を行うカスタムopenDrawerを作成した。 その際に、スクロール処理を行う箇所を特定するために、IDやdata属性を使って要素を特定した。 その後、スクロール処理を行うカスタムopenDrawerを作成した。

const scrollContainerRef = useRef<HTMLDivElement | null>(null)

// Drawerを開く際にスクロール処理を行うカスタムopenDrawer
const openDrawerAndScroll = useCallback(() => {
  originalOpenDrawer() // 元のロジックでDrawerを開く
  // @see: https://developer.mozilla.org/ja/docs/Web/API/Window/requestAnimationFrame
  requestAnimationFrame(() => {
    // IDやdata属性を使って要素を特定する (例: "filter-item-3-4")
    const elementId = "filter-item-year-month"←
    firstCheckedElement = document.getElementById(elementId)

    if (firstCheckedElement) {
      firstCheckedElement.scrollIntoView({
        behavior: 'instant',
        block: 'center', // 要素が中央に来るようにスクロール
      })
    }
  }
}

return (
  <Drawer isOpen={isDrawerOpen} onClose={closeDrawer}>
  <h2 className="mb-4 text-xl font-bold text-gray-800">フィルター</h2>
  <div
    ref={scrollContainerRef}
    className="h-[calc(100%-60px)] overflow-y-auto"
  >
    {Object.entries(months).map(([month, checked]) => (
      // idを年月にする
      <div key={month} id={"filter-item-year-month"}>{month}</div>
    ))}
  </div>
  </Drawer>
)