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

Redux Toolkit createApi如何合并解析多个接口端点的返回结果?

Redux Toolkit createApi多端点返回结果合并最佳实践

方案1:使用记忆化选择器(官方优先推荐)

该方案不需要额外编写reducer,所有合并逻辑放在数据层,完全不会污染视图代码,性能有保障。

  • 实现原理:通过createSelector创建记忆化派生数据选择器,从createApi的缓存中直接读取两个端点的返回结果,合并后供视图层调用,只有依赖的原始数据发生变化时才会重新计算合并结果。
  • 实现代码示例:
// apiSlice.js 你的createApi定义文件
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import { createSelector } from '@reduxjs/toolkit'

export const apiSlice = createApi({
  reducerPath: 'api',
  baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
  endpoints: (builder) => ({
    getUsers: builder.query({ query: () => '/users' }),
    getCars: builder.query({ query: () => '/cars' })
  })
})

export const { useGetUsersQuery, useGetCarsQuery } = apiSlice

// 定义两个端点的缓存结果选择器
const selectUsers = apiSlice.endpoints.getUsers.select()
const selectCars = apiSlice.endpoints.getCars.select()

// 定义合并逻辑的记忆化选择器
export const selectUserWithCars = createSelector(
  [selectUsers, selectCars],
  (usersRes, carsRes) => {
    // 仅在两个接口都请求成功时执行合并
    if (usersRes.isSuccess && carsRes.isSuccess) {
      // 此处替换为你的业务关联逻辑,示例为按用户ID关联名下车辆
      return usersRes.data.map(user => ({
        ...user,
        cars: carsRes.data.filter(car => car.userId === user.id)
      }))
    }
    return []
  }
)
  • 视图层调用示例:
import { useSelector } from 'react-redux'
import { useGetUsersQuery, useGetCarsQuery, selectUserWithCars } from './apiSlice'

function MixedPage() {
  // 触发两个接口请求,确保缓存中存在数据
  const { isLoading: usersLoading, error: usersErr } = useGetUsersQuery()
  const { isLoading: carsLoading, error: carsErr } = useGetCarsQuery()
  // 直接获取合并后的数据,无需在视图层写任何合并逻辑
  const mergedList = useSelector(selectUserWithCars)

  if (usersLoading || carsLoading) return <div>加载中</div>
  if (usersErr || carsErr) return <div>请求异常</div>

  return (
    <ul>
      {mergedList.map(item => (
        <li key={item.id}>
          <p>用户名:{item.name}</p>
          <div>
            {item.cars.map(car => <img key={car.id} src={car.imgUrl} alt={car.name} />)}
          </div>
        </li>
      ))}
    </ul>
  )
}

方案2:自定义Slice存储合并结果

如果需要对合并后的数据做独立的增删改操作,可以采用该方案,通过extraReducers监听createApi的请求成功回调,自动合并数据存入自定义slice。

  • 实现代码示例:
// mergedDataSlice.js
import { createSlice } from '@reduxjs/toolkit'
import { apiSlice } from './apiSlice'

const mergedDataSlice = createSlice({
  name: 'mergedUserCars',
  initialState: { data: [], status: 'idle' },
  reducers: {},
  extraReducers: (builder) => {
    // 监听用户接口请求成功事件
    builder.addMatcher(
      apiSlice.endpoints.getUsers.matchFulfilled,
      (state, { payload: users, meta }) => {
        const carsRes = apiSlice.endpoints.getCars.select()(meta.arg.getState())
        if (carsRes.isSuccess) {
          // 执行合并逻辑
          state.data = users.map(user => ({
            ...user,
            cars: carsRes.data.filter(car => car.userId === user.id)
          }))
          state.status = 'success'
        }
      }
    )
    // 监听车辆接口请求成功事件
    .addMatcher(
      apiSlice.endpoints.getCars.matchFulfilled,
      (state, { payload: cars, meta }) => {
        const usersRes = apiSlice.endpoints.getUsers.select()(meta.arg.getState())
        if (usersRes.isSuccess) {
          state.data = usersRes.data.map(user => ({
            ...user,
            cars: cars.filter(car => car.userId === user.id)
          }))
          state.status = 'success'
        }
      }
    )
  }
})

export default mergedDataSlice.reducer
  • 注意事项:需要将该slice的reducer注册到项目的root reducer中,视图层通过useSelector(state => state.mergedUserCars.data)即可直接读取合并后的数据。

方案选择建议

  • 绝大多数场景优先选择方案1,无需额外维护状态,代码量更少,记忆化选择器的性能足以支撑常规业务需求。
  • 仅当需要对合并后的数据做独立修改、且无需同步回原始接口缓存时,再选择方案2。

内容的提问来源于stack exchange,提问作者François Richard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 23:15:05