Redux State无法通过dispatch更新:移动端Roadmap滑动跳转异常
移动端Roadmap滑动切换阶段跳过中间项的修复方案
问题描述
开发反馈网站的Roadmap页面时,移动端实现了Planned、In-Progress、Live三个阶段的左右滑动切换功能,使用触摸滑动检测代码后出现异常:滑动到Live或Planned阶段后,尝试返回In-Progress阶段时会直接跳过该阶段,跳转到另一端的阶段。
复现步骤
- 使用开发者工具切换到移动端模式
- 点击菜单图标
- 点击Roadmap区块的view链接进入Roadmap路由
- 通过触摸滑动(可用鼠标模拟)切换到Live阶段
- 尝试滑动返回In-Progress阶段
问题根源
- 状态获取方式错误:事件监听中直接调用
store.getState()获取currentStage,未使用React-Redux的useSelector,导致组件无法响应Redux状态的更新,始终拿不到最新的阶段值。 - Effect依赖缺失:绑定滑动事件的
useEffect依赖项为空数组,事件回调函数会一直捕获初始的currentStage值,计算目标阶段时基于旧值判断,导致跳过中间阶段。
修复方案
1. 使用useSelector获取最新状态
替换直接调用store.getState()的方式,通过useSelector订阅Redux状态,确保组件能实时获取最新的currentStage值。
2. 为Effect添加正确依赖并优化回调
用useCallback包裹滑动处理函数,将currentStage和dispatch作为依赖项,确保状态更新时回调函数能拿到最新值;同时将包裹后的回调作为useEffect的依赖,保证事件监听能更新到最新的回调逻辑。
3. 限制滑动仅切换相邻阶段
在滑动处理逻辑中,基于当前阶段的索引计算目标阶段,限制每次滑动只能切换到前一个或后一个阶段,避免跨阶段跳转。
代码示例
修改后的RoadmapStages组件
import { useCallback, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { setCurrentStage } from '../features/roadmap/roadmapSlice'; const RoadmapStages = () => { const dispatch = useDispatch(); // 使用useSelector获取最新的currentStage const currentStage = useSelector(state => state.roadmap.currentStage); const stageOrder = ['Planned', 'In-Progress', 'Live']; // 用useCallback包裹滑动处理函数,依赖currentStage和dispatch const handleStageSwitch = useCallback((direction) => { const currentIndex = stageOrder.indexOf(currentStage); let newIndex; if (direction === 'left') { // 左滑:切换到下一个阶段,不能超过最后一个索引 newIndex = Math.min(stageOrder.length - 1, currentIndex + 1); } else if (direction === 'right') { // 右滑:切换到上一个阶段,不能小于0 newIndex = Math.max(0, currentIndex - 1); } dispatch(setCurrentStage(stageOrder[newIndex])); }, [currentStage, dispatch]); useEffect(() => { let touchStartX = 0; let touchEndX = 0; const handleTouchStart = (e) => { touchStartX = e.changedTouches[0].screenX; }; const handleTouchEnd = (e) => { touchEndX = e.changedTouches[0].screenX; const swipeThreshold = 50; // 滑动距离阈值,避免误触 const diff = touchStartX - touchEndX; if (Math.abs(diff) > swipeThreshold) { handleStageSwitch(diff > 0 ? 'left' : 'right'); } }; window.addEventListener('touchstart', handleTouchStart); window.addEventListener('touchend', handleTouchEnd); return () => { window.removeEventListener('touchstart', handleTouchStart); window.removeEventListener('touchend', handleTouchEnd); }; }, [handleStageSwitch]); // 依赖handleStageSwitch,确保回调更新 // 渲染各阶段内容 return ( <div className="roadmap-stages"> {/* 根据currentStage渲染对应阶段的内容 */} {stageOrder.map(stage => ( <div key={stage} className={`stage ${currentStage === stage ? 'active' : ''}`} > <h2>{stage}</h2> {/* 阶段内容 */} </div> ))} </div> ); }; export default RoadmapStages;
Roadmap Redux Slice定义
import { createSlice } from '@reduxjs/toolkit'; const initialState = { currentStage: 'In-Progress' // 默认显示中间阶段 }; const roadmapSlice = createSlice({ name: 'roadmap', initialState, reducers: { setCurrentStage: (state, action) => { state.currentStage = action.payload; } } }); export const { setCurrentStage } = roadmapSlice.actions; export default roadmapSlice.reducer;
说明
修改后,组件会实时响应Redux状态的变化,滑动时只会切换到相邻的阶段,解决了跳过In-Progress的问题。同时添加了滑动距离阈值,能有效避免误触导致的不必要切换。
内容的提问来源于stack exchange,提问作者TAGOPI
相关产品推荐
相关产品推荐

