You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建React Hook跟踪页面滚动深度并在组件卸载时正确记录最大值?

解决React Hook跟踪滚动深度在组件卸载时获取正确值的问题

问题描述

我正在开发一个用于跟踪用户页面最大滚动深度的React Hook,希望在组件卸载时通过useEffect的清理函数记录这个最大值。目前Hook本身能正常工作,但在Home组件里使用时遇到以下问题:

  • 若给useEffect的依赖数组添加maxScrollDepth,滚动时会持续打印日志;
  • 若依赖数组为空,组件卸载时仅打印初始值0。
    需要实现组件卸载时仅打印一次正确的最大滚动深度。

原代码

useTrackScrollDepth Hook

import { useEffect, useRef } from 'react';

export const useTrackScrollDepth = () => {
  const scrollDepthRef = useRef(0);

  const trackScrollDepth = () => {
    const scrolledValue = window.scrollY;

    scrollDepthRef.current = Math.max(scrolledValue, scrollDepthRef.current);
  };

  useEffect(() => {
    const handleScrollTracking = () => {
      trackScrollDepth();
    };

    document.addEventListener('scroll', handleScrollTracking);

    return () => {
      document.removeEventListener('scroll', handleScrollTracking);
    };
  }, []);

  return scrollDepthRef.current;
};

Home组件使用代码

import React, { useEffect } from 'react';

import { useTrackScrollDepth } from 'hooks/useTrackScrollDepth';

export function Home() {
  
  const maxScrollDepth = useTrackScrollDepth();

  useEffect(
    () => () => {
      console.log(`Max scroll depth: ${maxScrollDepth}`);
    },
    [],
  );

  return (
    <div>Home placeholder</div>
  );
}

解决方案

1. 修改useTrackScrollDepth Hook,返回ref对象

直接返回scrollDepthRef.current会导致组件每次渲染拿到的是快照值,无法实时获取最新滚动深度。改为返回ref对象,让外部可以直接访问最新的current属性:

import { useEffect, useRef } from 'react';

export const useTrackScrollDepth = () => {
  const scrollDepthRef = useRef(0);

  const trackScrollDepth = () => {
    const scrolledValue = window.scrollY;
    scrollDepthRef.current = Math.max(scrolledValue, scrollDepthRef.current);
  };

  useEffect(() => {
    const handleScrollTracking = () => {
      trackScrollDepth();
    };

    document.addEventListener('scroll', handleScrollTracking);

    return () => {
      document.removeEventListener('scroll', handleScrollTracking);
    };
  }, []);

  // 返回ref对象,而非current值
  return scrollDepthRef;
};

2. 在Home组件中通过ref访问最新值

组件中拿到ref后,在卸载清理函数中直接读取ref.current,依赖数组保持为空即可确保仅在卸载时执行一次:

import React, { useEffect } from 'react';
import { useTrackScrollDepth } from 'hooks/useTrackScrollDepth';

export function Home() {
  const maxScrollDepthRef = useTrackScrollDepth();

  useEffect(
    () => () => {
      console.log(`Max scroll depth: ${maxScrollDepthRef.current}`);
    },
    [], // 依赖数组为空,仅在组件卸载时执行清理函数
  );

  return (
    <div>Home placeholder</div>
  );
}

原理说明

  • ref对象的引用在组件生命周期内不会改变,因此返回ref不会触发组件不必要的重渲染;
  • 卸载时读取ref.current,能直接获取到滚动过程中更新的最新最大滚动深度;
  • 依赖数组为空,确保清理函数仅在组件卸载时执行一次,避免滚动时重复打印日志。

内容的提问来源于stack exchange,提问作者jcarapia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 21:12:48