You need to enable JavaScript to run this app. 如何在自定义React Hook中编写适配不同滚动目标的整洁条件逻辑?
优惠活动
大模型
产品
解决方案
定价
更多

如何在自定义React Hook中编写适配不同滚动目标的整洁条件逻辑?

滚动目标双适配的整洁实现方案

核心要解决window和DOM元素的垂直滚动位置获取API不统一问题,同时修正原有示例代码里的变量不匹配、依赖缺失、逻辑冗余问题。

具体优化点

  • 封装统一的滚动取值工具函数,完全隔离两类目标的API差异,避免在事件回调里散落判断逻辑
  • 修正原有代码的变量错误:原代码中引用的scrollRef.current与实际定义的myRef不匹配,会直接触发未定义报错
  • 收敛重复的状态赋值逻辑,去掉无意义的if-else分支,直接将阈值比较结果传入state更新函数
  • 补全effect的依赖项,避免闭包带来的目标值读取异常
  • 初始执行一次滚动回调,避免DOM挂载时初始滚动位置已经超过阈值、但状态不更新的问题

优化后完整代码

import { useState, useEffect, useRef } from 'react';

type ScrollTarget = 'ref' | 'window';

// 统一获取垂直滚动位置
const getScrollTopValue = (target: HTMLElement | Window): number => {
  if (target === window) {
    return window.pageYOffset;
  }
  return target.scrollTop;
};

const useMyHook = (target: ScrollTarget) => {
  const [fade, setFade] = useState(false);
  const myRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const scrollNode = target === 'ref' ? myRef.current : window;
    // 节点未挂载时跳过事件绑定
    if (!scrollNode) return;

    const onScroll = () => {
      const currentTop = getScrollTopValue(scrollNode);
      setFade(currentTop > 50);
    };

    // 初始化校验一次滚动位置
    onScroll();
    scrollNode.addEventListener('scroll', onScroll);

    return () => {
      scrollNode.removeEventListener('scroll', onScroll);
    };
  }, [target]);

  return { myRef, fade };
};

export default useMyHook;

注意事项

  • 因为ref的current属性变化不会触发组件重渲染,当目标为ref类型时,要确保DOM节点已经挂载到ref上,否则effect执行时会因为拿不到节点跳过事件绑定。常规静态DOM场景下这个逻辑完全可用。
  • 类型层面的收窄可以帮TypeScript正确识别两类目标的属性访问,避免TS报“scrollTop不存在于window、pageYOffset不存在于HTMLElement”的类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 07:45:04