如何在Redux中间件中启动RTK Query轮询?
无需React Hooks的RTK Query轮询最佳实践
核心思路:靠RTK Query的initiate方法+Redux中间件管理轮询生命周期
不用React Hooks的话,直接通过RTK Query的initiate创建订阅,结合中间件来启动、停止轮询,同时监听返回数据判断是否达到终止条件——全程不用依赖组件渲染循环,还能让所有组件共享逻辑,不用重复写代码。
具体实现步骤
1. 先在API切片里定义好要轮询的端点
确保你的RTK Query API切片已经包含目标查询端点,比如:
// apiSlice.js import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const apiSlice = createApi({ reducerPath: 'api', baseQuery: fetchBaseQuery({ baseUrl: '/api' }), endpoints: (builder) => ({ checkTaskStatus: builder.query({ query: (taskId) => `/tasks/${taskId}/status`, }), }), });
2. 编写Redux中间件处理轮询逻辑
让中间件监听触发轮询的action,调用initiate创建订阅并设置轮询间隔,每次收到数据后判断是否满足终止条件,满足就取消订阅:
// pollingMiddleware.js import { apiSlice } from './apiSlice'; const pollingMiddleware = (store) => (next) => (action) => { // 监听你定义的触发轮询的action,比如'task/startPolling' if (action.type === 'task/startPolling') { const { taskId, stopCondition } = action.payload; // 调用initiate创建订阅,设置轮询间隔(这里是3秒一次) const subscription = store.dispatch( apiSlice.endpoints.checkTaskStatus.initiate(taskId, { pollingInterval: 3000, onCacheEntryAdded: async (args, { cacheDataLoaded, cacheEntryRemoved }) => { try { await cacheDataLoaded; // 订阅Redux Store,监听数据变化 const unsubscribeStore = store.subscribe(() => { const state = store.getState(); // 获取当前查询的最新数据 const { data, isSuccess } = apiSlice.endpoints.checkTaskStatus.select(args)(state); if (isSuccess && stopCondition(data)) { // 满足终止条件,取消所有订阅 unsubscribeStore(); subscription.unsubscribe(); // 可以派发一个轮询完成的action,通知其他逻辑 store.dispatch({ type: 'task/pollingCompleted', payload: { taskId, data } }); } }); await cacheEntryRemoved; unsubscribeStore(); } catch (err) { // 出错时也记得取消订阅,避免内存泄漏 subscription.unsubscribe(); } }, }) ); } return next(action); }; export default pollingMiddleware;
3. 把中间件加入Redux Store
创建Store时把这个中间件和RTK Query自带的中间件一起加进去:
// store.js import { configureStore } from '@reduxjs/toolkit'; import { apiSlice } from './apiSlice'; import pollingMiddleware from './pollingMiddleware'; export const store = configureStore({ reducer: { [apiSlice.reducerPath]: apiSlice.reducer, // 其他业务reducer... }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(apiSlice.middleware, pollingMiddleware), });
关键细节说明
pollingInterval的作用:设置后RTK Query会自动按间隔发请求,不用你手动写定时器,直到订阅被取消。- 订阅的清理:必须在满足条件或缓存条目移除时取消订阅,不然会导致内存泄漏。
- 组件无感知:组件只需要派发
task/startPolling这个action就行,完全不用关心轮询的具体逻辑。
进阶替代方案:直接操作查询缓存控制轮询
如果需要更灵活地启停轮询,也可以用RTK Query内部的startPolling和stopPolling方法,直接操作查询缓存:
// 在中间件里的逻辑 const queryCache = store.dispatch(apiSlice.util.getQueryCache()); const queryKey = apiSlice.endpoints.checkTaskStatus.buildQueryKey(taskId); // 启动轮询,间隔3秒 queryCache.startPolling(queryKey, 3000); // 监听数据变化,满足条件就停止轮询 const unsubscribe = store.subscribe(() => { const { data, isSuccess } = apiSlice.endpoints.checkTaskStatus.select(taskId)(store.getState()); if (isSuccess && stopCondition(data)) { queryCache.stopPolling(queryKey); unsubscribe(); } });
这种方式适合需要动态调整轮询间隔、或者手动控制启停的场景。
内容的提问来源于stack exchange,提问作者krulik
相关产品推荐
相关产品推荐

