Back to blog
Apr 22, 2022
3 min read

【React】ページ上部では表示しないトップへ戻るボタンを作る【外部ライブラリなし】

Reactでページの一番上へなめらかに遷移するコンポーネントを作りませんか?むやみにライブラリをインストールせずとも実装できます。具体的なソースコードとその解説を行います。

はじめに

こんにちは!ブックマークしたサイトをやっと整理したこふです。

この記事では、本ブログの右下にもある「ページの一番上へ戻るボタン」の作り方を解説します。

![デモ Gif 画像 attachments/1.gif)


注意 ❗

以下の実装がベストプラクティスとは限りませんので、あくまで参考になさってください。


環境

React 以外の外部ライブラリは当然用いません。当然、Next.jsGatsby.js に組み込めます。

 node -v
v16.14.0

アイコンは各自で svg ファイルを読み込む・書き込むで対応 OK です

{
  "dependencies": {
    ...
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-icons": "^4.3.1",
    ...
  },
  "devDependencies": {
    ...
    "autoprefixer": "^10.4.0",
    "postcss": "^8.4.5",
    "tailwindcss": "^3.0.7",
    "typescript": "4.5.4"
    ...
  }
}

ソースコード

実際のソースコードです。動作確認済み。

import { useEffect, useState } from 'react'
import { HiChevronDoubleUp } from 'react-icons/hi'
import IconButton from '../IconButton/IconButton'

const PAGE_Y_OFFSET = 200

const ScrollToTop = () => {
  const [show, setShow] = useState<boolean>(false)

  const changeShow = () => {
    if (window.pageYOffset > PAGE_Y_OFFSET) {
      setShow(true)
    } else {
      setShow(false)
    }
  }

  const onScrollTop = () => {
    window.scroll({ top: 0, behavior: 'smooth' })
  }

  useEffect(() => {
    window.addEventListener('scroll', changeShow)
    return () => window.removeEventListener('scroll', changeShow)
  }, [])

  if (show)
    return (
      <div className="fixed bottom-10 right-10 z-10">
        <IconButton Icon={HiChevronDoubleUp} onClick={onScrollTop} />
      </div>
    )
  else return null
}

export default ScrollToTop

ソースコードの解説

本来は UI とロジックが混在すべきでないですが、簡単のためファイルは 1 つにします。

ライブラリ群

import { useEffect, useState } from "react";
import { HiChevronDoubleUp } from "react-icons/hi";
import IconButton from "../IconButton/IconButton";

必要なライブラリをインポートします。

トップへ戻るボタンの表示・非表示を管理する状態を保持するための useStatescroll 位置を監視するための副作用として useEffect を利用します。

IconButton は自分で作っているアイコンをボタンデザインで表示するコンポーネントです。

状態管理

const [show, setShow] = useState<boolean>(false);

論理値で表示・非表示を管理します。

表示・非表示を変更する関数

const PAGE_Y_OFFSET_LIMIT = 200;

const changeShow = () => {
  if (window.pageYOffset > PAGE_Y_OFFSET_LIMIT) {
    setShow(true);
  } else {
    setShow(false);
  }
};

DOMwindow オブジェクトから Y 方向(縦方向)のスクロール位置と、定義した Y 方向の境界とする値を比較し、表示・非表示を決める関数を定義します。

定数値なので、他の定数ファイルから読み込むと良いです。

参考:https://developer.mozilla.org/en-US/docs/Web/API/Window/pageYOffset

ページ上部へ遷移する関数

const onScrollTop = () => {
  window.scroll({ top: 0, behavior: "smooth" });
};

window オブジェクトの scroll 関数(メソッド)を呼び出してスクロールします。

参考:https://developer.mozilla.org/ja/docs/Web/API/Window/scroll

スクロールを監視する副作用である useEffect

useEffect(() => {
  window.addEventListener("scroll", changeShow);
  return () => window.removeEventListener("scroll", changeShow);
}, []);

useEffect の第二引数に空の配列を渡して、最初にコンポーネントがマウントされた時に window オブジェクトに scroll イベントを追加します。

return 以降でアンマウント時(コンポーネントを使わなくなるようなこと)に、そのイベントを削除します。

注意点

常にスクロールを監視するのはパフォーマンス上良くない場合がありますので、ご注意ください。

100ms ごとにスクロール監視などで十分かと思います。


また、Internet Explore などの古いブラウザ、Safari ではスムーズ遷移するとは限りません。

その場合は、以下のような Polyfill ライブラリを使ってください。

僕自身は、ページ上部へ戻る時の動きに価値はないと考えています。そのため外部ライブラリを使うことはしません。

https://github.com/wessberg/scroll-behavior-polyfill

他のやり方

無数にありますが、結局やりたいことは同じなので代わり映えしません。

例えば以下の方法があります。

  • react-scroll などのライブラリを用いる
  • a タグで href='#'としページトップへ遷移する

おわりに

以上でこのサイトの右下のようなページ遷移が完成します。

気軽にご自身のサイトに取り入れてみてください。

参考