React でページ内の目的の箇所まで自動スクロールさせる

React で作成したページに一覧が表示されているときに、一覧の最後までスクロールさせる方法。 React.createRef() で作成した ref と ref.current.scrollIntoView() を組み合わせて実装するだけです。
2020.04.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

「React で作ったページ内を自動スクロールさせたい」とたまに質問を受けるのでまとめました。

やりたいこと

React で作成したページに一覧が表示されているときに、一覧の最後までスクロールさせたい。 または目的の箇所までスクロールさせたい。

環境

  • React 16.13.1
  • TypeScript

コードと説明

CodePen 上の動くサンプルコード

  1. スクロールして表示したい箇所に React の Element をつくる (div など)
  2. React.createRef() で ref を作り、作った Element に ref をセット
  3. ref.current.scrollIntoView() で Element までスクロール
// <List /> の中身は CodePen のサンプルコード参照

const ListPage: React.FC = () => {
  // 表示するリストのデータを 100 個用意 (本当なら API 経由で取ってくる箇所)
  // const items: Item[] = [{ title: "number-0" }, { title: "number-1" }, ...]
  const items: Item[] = [...Array(100)].map((_, i) => {
    return { title: `number-${i}` }
  });

  // ref を作成しスクロールさせたい場所にある Element にセット
  const ref = React.createRef<HTMLDivElement>()
  // このコールバックを呼び出して ref.current.scrollIntoView() を呼び出してスクロール
  const scrollToBottomOfList = React.useCallback(() => {
    ref!.current!.scrollIntoView({
      behavior: 'smooth',
      block: 'end',
    })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [ ref ])

  // useEffect() 内はページが描画されたあとに呼び出される
  React.useEffect(()=>{
    // ページが描画されたらリストの末尾までスクロール
    scrollToBottomOfList()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  return (
    <div>
      <List items={items} />
      <div id="bottom-of-list" ref={ref} />
    </div>
  )
}

このコードでは useEffect を使ってページ描画時に自動スクロールしていますが、 scrollToBottomOfList() を呼び出せばスクロールできるのでボタンがクリックされたときや、 ボタンをクリックした後データの読み込みが完了した後にスクロールすることもできます。

const handleClick = React.useCallback(() => {
  scrollToBottomOfList()
}, [])
// ...
// <button onClick={handleClick} />いちばん下までスクロール</button>

スクロール先を変えたいときは ref={ref} をセットしている Element の場所を変えるなどして対応します。

注意点

ページ内を強制的にスクロールするというのは、ページの利用者にとっては意図しない動作で使いにくいことがあります。 今表示されている箇所を見てるのに、勝手にスクロールされてどこを見てたのか分からなくなる、、なんて体験はよくあると思います。 (サンプルコードではページ表示時に自動スクロールしていますが) ユーザーのスクロールしたいという意思表示の操作があってからスクロールさせるようにしてください。

参考