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

如何使用RTK Query从两个关联端点获取并合并数据?

问题翻译与解决方案

问题(翻译后)

我有两个API端点:
GET /api/messages/:userId/latest 和 GET /api/messages/:userId/:page

当应用加载页面时,会先调用第一个端点获取特定用户需要加载的页码信息,示例响应如下:

{
   pages: [324, 325, 326]
}

随后,会使用从第一个端点获取的参数多次调用第二个端点。

我的问题是:如何在Redux-Toolkit(RTK)Query中定义一个查询,实现上述调用流程并合并结果?

我的代码片段:

export interface MessageApiParams {
  userId: String | undefined,
  page: number
}

export const baseQuery = fetchBaseQuery({
  baseUrl: '/api',
  prepareHeaders: (headers) => {
    const token = getAccessToken()?.token
    if (token) {
      headers.set("authorization", `Bearer ${token}`);
    }
    return headers;
  },
})

export const messagesApi = createApi({
  reducerPath: 'messagesApi',
  baseQuery: baseQuery,
  endpoints: builder => ({
    getMessages: builder.query<Messages, MessageApiParams>({
      query: (params: MessageApiParams) => {
        return ({
          url: `/users/${params.userId}/messages/${params.page}`,
          method: 'GET',
          headers: { Authorization: `Bearer ${getAccessToken()?.token}`}
        });
      }
    })
  })
})

解决方案

要实现先获取页码再批量请求消息并合并结果的流程,你可以使用RTK Query的queryFn编写自定义查询逻辑,它允许在单个查询中处理多步异步请求。

1. 补充类型定义

先完善类型确保代码安全:

// 最新页码接口的响应类型
interface LatestPagesResponse {
  pages: number[];
}

// 单页消息的响应结构(根据你的实际业务调整字段)
interface PageMessages {
  id: string;
  content: string;
  senderId: string;
  // ...其他消息字段
}

// 最终合并后的消息数组类型
type Messages = PageMessages[];

// 查询参数仅需userId,页码由接口动态获取
interface GetAllMessagesParams {
  userId: string | undefined;
}

2. 修改API端点定义

替换原有的getMessages端点,用queryFn实现两步请求逻辑:

export const messagesApi = createApi({
  reducerPath: 'messagesApi',
  baseQuery: baseQuery,
  endpoints: builder => ({
    getAllMessages: builder.query<Messages, GetAllMessagesParams>({
      async queryFn({ userId }, _queryApi, _extraOptions, baseQuery) {
        // 校验用户ID是否存在
        if (!userId) {
          return { error: { status: 'CUSTOM_ERROR', error: '用户ID不能为空' } };
        }

        // 第一步:请求需要加载的页码列表
        const pagesResult = await baseQuery({
          url: `/messages/${userId}/latest`,
          method: 'GET'
        });

        if (pagesResult.error) {
          return { error: pagesResult.error };
        }

        const { pages } = pagesResult.data as LatestPagesResponse;
        if (!pages || pages.length === 0) {
          return { data: [] };
        }

        // 第二步:并行请求所有页码的消息数据
        const messageRequests = pages.map(page => 
          baseQuery({
            url: `/messages/${userId}/${page}`,
            method: 'GET'
          })
        );

        const messageResults = await Promise.all(messageRequests);

        // 合并所有有效消息,过滤请求失败的页码
        const allMessages: Messages = [];
        for (const result of messageResults) {
          if (!result.error) {
            allMessages.push(...(result.data as PageMessages[]));
          }
        }

        return { data: allMessages };
      }
    })
  })
});

// 导出自动生成的Hook供组件使用
export const { useGetAllMessagesQuery } = messagesApi;

3. 组件中使用示例

import { useGetAllMessagesQuery } from './path-to-your-api-file';

function UserMessages({ userId }: { userId: string }) {
  const { data: messages, isLoading, error } = useGetAllMessagesQuery({ userId });

  if (isLoading) return <div>加载消息中...</div>;
  if (error) return <div>消息加载失败:{(error as any).error}</div>;

  return (
    <div className="messages-list">
      {messages?.map(msg => (
        <div key={msg.id} className="message-item">
          <p>{msg.content}</p>
          <small>来自用户:{msg.senderId}</small>
        </div>
      ))}
    </div>
  );
}

关键说明

  • queryFn的灵活性:相比普通query,它支持自定义异步逻辑,适合多步请求场景。
  • 并行请求优化:用Promise.all同时请求所有页码,比串行请求效率更高。
  • 错误容错:分别处理用户ID缺失、页码请求失败、单页消息请求失败等情况,避免整个流程崩溃。
  • 缓存自动管理:RTK Query会自动缓存查询结果,相同用户ID的重复请求会直接返回缓存数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 10:43:17