0

0

基于滚动速度控制导航栏可见性的React Hook优化教程

霞舞

霞舞

发布时间:2025-08-19 17:02:01

|

792人浏览过

|

来源于php中文网

原创

基于滚动速度控制导航栏可见性的react hook优化教程

本文将介绍如何创建一个React Hook,用于根据滚动位置、滚动方向和滚动速度来控制导航栏的可见性,实现类似Humboldt forum网站的交互效果。我们将详细分析原始Hook的实现,并提供优化后的版本,重点关注性能提升,包括使用useCallback进行函数记忆,以及依赖项的合理设置,确保Hook在必要时才更新。

创建基于滚动速度的导航栏可见性控制Hook

在Web开发中,根据用户的滚动行为动态调整导航栏的可见性是一种常见的交互模式,能够提升用户体验。本教程将引导你创建一个React Hook,实现以下功能:

  1. 导航栏初始时固定在页面顶部。
  2. 当用户向下滚动时,隐藏导航栏。
  3. 当用户向上快速滚动时,重新显示导航栏。
  4. 导航栏始终在页面顶部可见。

原始Hook的实现与分析

以下是原始Hook的代码:

const useScrollSpeed = (navHeight: number, maxScrollSpeed: number) => {

  const [lastScrollTime, setLastScrollTime] = useState(new Date().getTime());
  const [currentScrollPos, setCurrentScrollPos] = useState(0)
  const [prevScrollPos, setPrevScrollPos] = useState(0);
  const [visible, setVisible] = useState(true);

  const handleScroll = () => {
    const distance = Math.abs(currentScrollPos - prevScrollPos);
    const scrollSpeed = distance / (new Date().getTime() - lastScrollTime);


      if (currentScrollPos > prevScrollPos) {
        setVisible(false);
      } else {
        if (scrollSpeed > maxScrollSpeed) {
          setVisible(true);
        }
      }

    setPrevScrollPos(currentScrollPos);
    setLastScrollTime(new Date().getTime());
  };

  if (typeof window !== "undefined") {
    useEffect(() => {
      setCurrentScrollPos(window.scrollY)

      if (currentScrollPos < navHeight) {
        setVisible(true);
      } 
      window.addEventListener("scroll", handleScroll);
      return () => window.removeEventListener("scroll", handleScroll);
    }, [window.scrollY]);
  }


  return visible;
};
export default useScrollSpeed;

这段代码存在一些潜在的性能问题:

  • handleScroll函数在每次滚动事件触发时都会重新创建,导致不必要的函数重新渲染。
  • useEffect的依赖项window.scrollY会导致每次滚动都会触发useEffect,这可能会导致性能问题。

优化后的Hook实现

为了解决上述问题,我们可以使用useCallback来记忆handleScroll函数,并优化useEffect的依赖项。

Miniflow
Miniflow

AI工作流自动化平台

下载
import { useState, useEffect, useCallback } from 'react';

const useScrollSpeed = (navHeight: number, maxScrollSpeed: number) => {
  const [lastScrollTime, setLastScrollTime] = useState(new Date().getTime());
  const [currentScrollPos, setCurrentScrollPos] = useState(0);
  const [prevScrollPos, setPrevScrollPos] = useState(0);
  const [visible, setVisible] = useState(true);

  const handleScroll = useCallback(() => {
    const now = new Date().getTime();
    const distance = Math.abs(currentScrollPos - prevScrollPos);
    const scrollSpeed = distance / (now - lastScrollTime);

    if (currentScrollPos > prevScrollPos) {
      setVisible(false);
    } else {
      if (scrollSpeed > maxScrollSpeed) {
        setVisible(true);
      }
    }

    setPrevScrollPos(currentScrollPos);
    setLastScrollTime(now);
  }, [currentScrollPos, prevScrollPos, lastScrollTime, setVisible, maxScrollSpeed]);

  useEffect(() => {
    const handleInitialScroll = () => {
      setCurrentScrollPos(window.scrollY);
      if (window.scrollY < navHeight) {
        setVisible(true);
      }
    };

    handleInitialScroll(); // 初始化滚动位置和可见性

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [handleScroll, navHeight]);

  return visible;
};

export default useScrollSpeed;

优化说明:

  1. useCallback: 使用 useCallback 包裹 handleScroll 函数。这确保了只有当依赖项(currentScrollPos,prevScrollPos,lastScrollTime,setVisible,maxScrollSpeed)发生变化时,handleScroll 函数才会被重新创建。
  2. useEffect依赖项优化: 移除了window.scrollY作为useEffect的依赖项。取而代之的是,在useEffect内部添加了一个handleInitialScroll函数来初始化滚动位置和可见性,并只在组件挂载时执行一次。
  3. 代码可读性: 使用 now 变量存储当前时间,避免多次调用 new Date().getTime(),提高代码可读性。

使用示例

import useScrollSpeed from './useScrollSpeed';
import React, { useState, useEffect } from 'react';

const Navbar = () => {
  const navHeight = 60; // 导航栏高度
  const maxScrollSpeed = 0.5; // 最大滚动速度,用于判断是否快速向上滚动
  const isVisible = useScrollSpeed(navHeight, maxScrollSpeed);
  const [style, setStyle] = useState({
    top: 0,
    transition: 'top 0.3s',
    position: 'fixed',
    width: '100%',
    backgroundColor: 'white',
    zIndex: 1000
  });

  useEffect(() => {
    setStyle(prevStyle => ({
      ...prevStyle,
      top: isVisible ? 0 : `-${navHeight}px`
    }));
  }, [isVisible, navHeight]);


  return (
    
  );
};

export default Navbar;

在这个例子中,Navbar 组件使用 useScrollSpeed Hook 来判断导航栏是否应该可见。根据 isVisible 的值,动态地设置导航栏的 top 样式,实现显示和隐藏的动画效果。

注意事项

  • navHeight 和 maxScrollSpeed 的值需要根据实际情况进行调整。
  • 在复杂的应用中,可以考虑使用节流或防抖技术来进一步优化滚动事件的处理。
  • 确保在组件卸载时移除事件监听器,避免内存泄漏。

总结

通过使用 useCallback 和优化 useEffect 的依赖项,我们可以显著提升基于滚动速度控制导航栏可见性的React Hook的性能。优化后的Hook减少了不必要的函数重新创建和组件重新渲染,从而提高了应用的整体性能和用户体验。希望本教程能够帮助你更好地理解和应用React Hook。

相关专题

更多
c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

42

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

46

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

202

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

341

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

16

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

100

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

73

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

75

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

67

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 3万人学习

Django 教程
Django 教程

共28课时 | 3.5万人学习

Kotlin 教程
Kotlin 教程

共23课时 | 2.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号