Programming Journal

学習したことの整理用です。

【React】スクロールダウン・アップでボタンの非表示・表示を切り替える

概要

スクロールアップ時に表示され、スクロールダウン時に非表示になるButtonコンポーネントをつくりたい

スクロールボタン

要件・流れ

  • スクロールアップ ---ボタン表示
  • スクロールダウン ---ボタン非表示

  • 以前のスクロール位置をuseStateで保持する

  • ボタンの非表示・表示はdisplay: block display: noneを切り替えて管理する
  • 前回のスクロール位置が現在のスクロール位置よりも大きい場合、ボタンを表示する。これは、ユーザーがページを上にスクロールしていることと同意
export const ScrollButton = () => {
// ボタン表示・非表示の状態
  const [isVisible, setIsVisible] = useState(true);
// 前回のスクロール位置
  const [prevScrollPosition, setPrevScrollPosition] = useState(0);

  const handleScroll = () => {
// 現在のスクロール位置を取得
    const currentScrollPos = window.scrollY;
// 前回のスクロール位置が現在のスクロール位置よりも大きい場合、ボタンを表示する
    const isVisible = prevScrollPosition > currentScrollPos;

    setIsVisible(isVisible);
    setPrevScrollPosition(currentScrollPos);
  };

  useEffect(() => {
    window.addEventListener("scroll", handleScroll);

// クリーンアップ
    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, [handleScroll]);

  return (
    <button style={{ display: isVisible ? "block" : "none" }}>
      Float Button
    </button>
  );
};

Refactor

現在だとスクロールイベントが高頻度で発生してしまうため、パフォーマンスに影響を与えてしまう可能性がある。

そのため、debounce関数を使って、イベントを間引きして実行するように修正していく。

import React, { useState, useEffect } from "react";
import { debounce } from "lodash";

export const ScrollButton = () => {
  const [isVisible, setIsVisible] = useState(true);
  const [prevScrollPosition, setPrevScrollPosition] = useState(0);

  const handleScroll = () => {
    const currentScrollPos = window.scrollY;
    const isVisible = prevScrollPosition > currentScrollPos;
    setIsVisible(isVisible);
    setPrevScrollPosition(currentScrollPos);
    console.log("scroll");
  };

  const debounceHandleScroll = debounce(handleScroll, 100);

  useEffect(() => {
    window.addEventListener("scroll", debounceHandleScroll);

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

  return (
    <button style={{ display: isVisible ? "block" : "none" }}>
      Float Button
    </button>
  );
};

bounce関数使用前

scroll without bounce

bounce関数使用後

scroll with bounce

参考にしたサイト

React, Vue.js, JavaScriptでdebounceの仕組みを理解 | アールエフェクト