如何使用Redux Thunk实现基于setInterval、clearInterval的计时器功能
问题排查与解决方案
问题1:Reducer 不能包含副作用代码
Redux 明确要求 Reducer 必须是纯函数,相同输入要返回固定输出,不允许出现定时器、异步请求、修改外部变量这类副作用操作。你在 Reducer 中直接写setInterval的写法本身不符合 Redux 设计规范,必然无法正常运行。
问题2:Thunk 实现存在两处核心错误
你编写的 Thunk 代码有两个明显问题:
- 定时器ID没有持久化存储:
timer是函数内部局部变量,每次调用 Thunk 都会重新初始化,之前启动的定时器ID会直接丢失,clearInterval(timer)根本找不到正在运行的定时器,完全起不到停止计时的作用 - 判断逻辑倒置:你在
getState().isRunning === true的时候才启动定时器,但点击按钮是要切换运行状态,只有原本isRunning为false的时候才需要启动定时器,原本为true的时候应该清理定时器才对
正确实现方案
1. 给Store新增存储定时器ID的字段
修改 Reducer 初始状态和对应分支:
// 初始state新增timerId字段 const initialState = { count: 0, isRunning: false, timerId: null } const reducer = (state = initialState, action) => { switch(action.type) { case "TOGGLE_RUNNING": return { ...state, isRunning: !state.isRunning } case "SET_TIMER_ID": return { ...state, timerId: action.payload } case "INCREMENT": return { ...state, count: state.count + 1 } default: return state } }
2. 重写Thunk逻辑
export const timerHandler = () => (dispatch, getState) => { const { isRunning, timerId } = getState(); // 先清理已存在的定时器 if (timerId) { clearInterval(timerId); dispatch({ type: "SET_TIMER_ID", payload: null }); } // 切换运行状态 dispatch({ type: "TOGGLE_RUNNING" }); // 切换后为运行状态则启动新定时器 if (!isRunning) { const newTimerId = setInterval(() => { dispatch({ type: "INCREMENT" }); }, 1000); dispatch({ type: "SET_TIMER_ID", payload: newTimerId }); } }
3. 组件绑定无需修改
你的按钮代码保持不变,直接把props.timerHandler绑定上面重写的timerHandlerThunk即可正常使用。
内容的提问来源于stack exchange,提问作者cHappiness
相关产品推荐
相关产品推荐

