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

在React-Redux Reducer中通过addEventListener获取滚动值的疑问

如何在React-Redux中正确获取并存储滚动位置

嘿,我看到你在Redux reducer里处理滚动位置的时候踩了个小坑,咱们一步步来拆解问题、解决它~

首先得说清楚你当前代码里的几个关键问题:

  • Reducer必须是纯函数,绝对不能在里面执行window.addEventListener这种带有副作用的操作——这完全违背了Redux的数据流原则,而且addEventListener本身返回的是undefined,所以你赋值给test的结果就是undefined,自然没法拿到有效的滚动值。
  • 你在事件回调里返回scroll也没用,因为滚动监听的回调返回值根本不会被捕获到,相当于做了无用功。

接下来给你一套正确的实现方案:

第一步:在组件里监听滚动,派发Action

应该把滚动监听放在React组件(比如根组件或者需要监听滚动的特定组件)里,计算出滚动值之后,再派发给Redux Store。

示例代码:

import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import constants from './你的常量文件路径';

function ScrollTracker() {
  const dispatch = useDispatch();

  useEffect(() => {
    // 定义滚动处理函数
    const handleScroll = () => {
      let supportPageOffset = window.pageXOffset !== undefined;
      let isCSS1Compat = ((document.compatMode || '') === 'CSS1Compat');
      const scrollY = supportPageOffset 
        ? window.pageYOffset 
        : isCSS1Compat 
          ? document.documentElement.scrollTop 
          : document.body.scrollTop;
      
      // 把滚动值通过action派发给reducer
      dispatch({
        type: constants.SCROLL_POSY,
        payload: scrollY
      });
    };

    // 添加滚动监听
    window.addEventListener('scroll', handleScroll);
    
    // 组件卸载时一定要移除监听,防止内存泄漏
    return () => window.removeEventListener('scroll', handleScroll);
  }, [dispatch]);

  return null; // 这个组件不需要渲染任何可视内容
}

export default ScrollTracker;

第二步:修改Reducer处理Action

现在你的Reducer只需要接收Action里的滚动值,更新state就可以了,完全是纯函数操作:

import constants from './你的常量文件路径';

const initialState = {
  scrollY: 0 // 初始滚动位置设为0
};

const yourReducer = (state = initialState, action) => {
  switch (action.type) {
    case constants.SCROLL_POSY:
      // 直接用action.payload里的滚动值更新state
      return { ...state, scrollY: action.payload };
    default:
      return state;
  }
};

export default yourReducer;

可选优化:给滚动监听加节流

滚动事件触发频率特别高,频繁派发Action可能会影响性能,你可以用**节流(throttle)**来限制触发次数,比如用Lodash的throttle工具:

import { throttle } from 'lodash';

// 在useEffect里修改handleScroll:
const handleScroll = throttle(() => {
  // 计算scrollY的逻辑不变
  dispatch({ type: constants.SCROLL_POSY, payload: scrollY });
}, 100); // 每100ms触发一次,可根据需求调整时间

最后,你可以在任何需要用到滚动位置的组件里,用useSelector获取这个值:

import { useSelector } from 'react-redux';

function SomeComponent() {
  const scrollY = useSelector(state => state.yourReducer.scrollY);
  return <div>当前滚动位置:{scrollY}px</div>;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:35:31