离线时暂停与恢复Redux Thunk动作:createListenerMiddleware是否适用?
离线暂停Redux Thunk并联网恢复的解决方案
结论:createListenerMiddleware并非合适方案
createListenerMiddleware的核心是监听已派发完成的动作,它无法拦截thunk函数的执行,也没法控制调用方Promise的状态——因为thunk一旦被派发,要么已经开始执行,要么调用方的Promise已经处于pending/rejected状态,listener无法回溯修改这些逻辑,完全满足不了你“让调用方Promise直到联网后再resolve”的需求。
正确思路:自定义中间件拦截thunk+队列暂存
要实现离线时暂停thunk、联网后恢复执行,且保持调用方Promise挂起状态,需要从拦截thunk的执行时机入手,结合队列暂存thunk和对应的Promise回调。
1. 澄清:普通中间件可以拦截thunk
你之前的理解有误——普通中间件可以拦截thunk,关键是要把它放在redux-thunk中间件之前。因为thunk中间件的作用是判断action是否为函数,如果是就执行它;所以在它之前的中间件会先收到这个thunk函数,此时可以选择不传递给下一个中间件(即暂停执行)。
2. 具体实现步骤
第一步:创建网络状态与暂存队列的Slice
用Redux Toolkit维护在线状态和待执行的thunk队列:
import { createSlice } from '@reduxjs/toolkit'; const networkSlice = createSlice({ name: 'network', initialState: { isOnline: navigator.onLine, pendingThunks: [] }, reducers: { setOnlineStatus: (state, action) => { state.isOnline = action.payload; }, addPendingThunk: (state, action) => { state.pendingThunks.push(action.payload); }, clearPendingThunks: (state) => { state.pendingThunks = []; } } }); export const { setOnlineStatus, addPendingThunk, clearPendingThunks } = networkSlice.actions; export default networkSlice.reducer;
第二步:编写自定义离线拦截中间件
这个中间件会拦截thunk函数,离线时暂存,在线时放行:
const offlineThunkMiddleware = (store) => (next) => (action) => { // 判断当前action是否为thunk函数 if (typeof action === 'function') { const { isOnline } = store.getState().network; if (!isOnline) { // 返回一个挂起的Promise,直到联网后执行thunk再resolve/reject return new Promise((resolve, reject) => { store.dispatch(addPendingThunk({ thunk: action, resolve, reject })); }); } } // 在线状态下,直接交给后续中间件(thunk中间件)处理 return next(action); };
第三步:配置Store,将自定义中间件放在thunk之前
确保自定义中间件先于thunk中间件执行:
import { configureStore } from '@reduxjs/toolkit'; import thunk from 'redux-thunk'; import networkReducer from './networkSlice'; import offlineThunkMiddleware from './offlineThunkMiddleware'; export const store = configureStore({ reducer: { network: networkReducer, // 你的其他reducer... }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().prepend(offlineThunkMiddleware).concat(thunk) });
第四步:监听网络状态变化,执行暂存的thunk
在应用初始化时监听在线/离线事件,联网后批量执行队列中的thunk:
// 监听在线事件 window.addEventListener('online', async () => { store.dispatch(setOnlineStatus(true)); const { pendingThunks } = store.getState().network; // 依次执行每个暂存的thunk,并触发对应的Promise回调 for (const { thunk, resolve, reject } of pendingThunks) { try { const result = await thunk(store.dispatch, store.getState, undefined); resolve(result); } catch (error) { reject(error); } } store.dispatch(clearPendingThunks()); }); // 监听离线事件 window.addEventListener('offline', () => { store.dispatch(setOnlineStatus(false)); });
方案优势
- 完全基于Redux Toolkit和原生API,无需依赖第三方库,避免维护和类型问题
- 调用方的Promise会一直挂起,直到联网后thunk执行完成才resolve/reject,不会提前触发错误
- 逻辑可控,队列中的thunk可以按顺序执行,也可根据需求调整执行策略
内容的提问来源于stack exchange,提问作者uloco
相关产品推荐
相关产品推荐

