You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合Redux Offline与RTK-Query处理离线请求

Redux Offline 与 RTK Query 结合实现方案

已经有成熟的生产实践实现二者结合,核心需求(离线时失败的POST类mutation入队、联网后自动重放)不需要硬套传统Redux Offline手动编写带offline meta的action的模式——RTK Query的mutation是内部自动生成action、托管请求生命周期的,手动给触发的action加offline meta会打断RTK Query自带的loading、缓存更新逻辑,适配思路是复用Redux Offline的网络状态监听、离线队列能力,请求发送和状态管理完全交给RTK Query处理。

具体实现步骤

  • 保留Redux Offline基础配置,保留其outbox队列、网络状态检测核心逻辑,关闭其自带的默认请求发送effect,避免和RTK Query的请求逻辑冲突。
  • 封装离线感知的自定义baseQuery:请求发起前先读取store中Redux Offline维护的网络状态,如果当前离线,就把当前mutation的endpoint名称、请求参数存入Redux Offline的outbox队列,同时返回一个持续pending的Promise,让UI层维持加载状态,不直接抛出请求失败错误。
  • 监听store状态变化,当检测到网络从离线切为在线、且outbox队列中存在待处理的RTK Query mutation记录时,依次用存储的endpoint和参数重新触发对应mutation,请求完成后将对应记录从队列中移除。
  • 乐观更新、请求成功/失败的状态回滚直接使用RTK Query自带的onQueryStarted生命周期钩子实现,不需要手动编写commit、rollback类的action,RTK Query会自动管理缓存更新与回滚。

核心实现代码示例

离线感知的自定义baseQuery与API定义

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import { offlineActions } from '@redux-offline/redux-offline'

const baseQuery = fetchBaseQuery({ baseUrl: '/api' })

const offlineAwareBaseQuery = async (args, api, extraOptions) => {
  const isOnline = api.getState().offline.online
  // 离线状态将请求加入队列
  if (!isOnline) {
    api.dispatch(offlineActions.outbox.enqueue({
      type: 'RTK_QUERY_PENDING_MUTATION',
      meta: {
        rtkQuery: {
          endpointName: api.endpoint,
          args,
          extraOptions
        },
        offline: { effect: {}, commit: {}, rollback: {} } // 占位,阻止Redux Offline自动发送请求
      }
    }))
    // 返回pending状态维持mutation加载态
    return new Promise(() => {})
  }
  // 在线状态正常发起请求
  return baseQuery(args, api, extraOptions)
}

export const api = createApi({
  baseQuery: offlineAwareBaseQuery,
  endpoints: (builder) => ({
    registerUser: builder.mutation({
      query: (userData) => ({
        url: '/register',
        method: 'POST',
        body: new URLSearchParams(userData).toString(),
        headers: { 'content-type': 'application/x-www-form-urlencoded' }
      }),
      // 乐观更新逻辑与普通RTK Query写法完全一致
      async onQueryStarted(userData, { dispatch, queryFulfilled }) {
        const patchResult = dispatch(
          api.util.updateQueryData('getUserList', undefined, (draft) => {
            draft.push(userData)
          })
        )
        try {
          await queryFulfilled
        } catch {
          patchResult.undo()
        }
      }
    })
  })
})

export const { useRegisterUserMutation } = api

联网后自动重放队列逻辑

// store初始化后添加全局监听
let prevOnlineState = store.getState().offline.online
store.subscribe(() => {
  const currentState = store.getState().offline
  // 检测到从离线切为在线时处理队列
  if (!prevOnlineState && currentState.online && currentState.outbox.length > 0) {
    currentState.outbox.forEach(queueItem => {
      if (queueItem.type === 'RTK_QUERY_PENDING_MUTATION') {
        const { endpointName, args } = queueItem.meta.rtkQuery
        // 重发mutation
        store.dispatch(api.endpoints[endpointName].initiate(args))
        // 移除已处理的队列项
        store.dispatch(offlineActions.outbox.dequeue(queueItem))
      }
    })
  }
  prevOnlineState = currentState.online
})

业务层使用mutation时和普通RTK Query写法没有区别,不需要为每个请求单独编写offline meta配置,通用逻辑已经封装在baseQuery和全局监听中。

内容的提问来源于stack exchange,提问作者cseelus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 18:15:44