在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
相关产品推荐
相关产品推荐

