如何使用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
相关产品推荐
相关产品推荐

