在Next.js的generateMetadata中正确使用RTK Query查询的问题
问题描述
在Next.js项目中使用RTK Query,需要在generateMetadata中实现数据查询功能。不想额外引入Axios,希望复用RTK Query的请求逻辑,将数据存入store后取用,但当前写法存在问题,需要排查错误原因。
我的RTK API代码:
export const pastEventsApi = rtkQueryApi.injectEndpoints({ endpoints: (builder) => ({ getVideo: builder.query<Filters, string>({ query: (id) => ({ url: `/pro/ru/block/get_selected_video?uid=${id}`, }), }), }), });
尝试的generateMetadata代码:
export const generateMetadata = async ({ params }: Params) => { const { id } = params; const res = await pastEventsApi.endpoints.getVideo.initiate(id); return { title: res?.data?.title, }; };
错误原因与解决方法
核心错误
pastEventsApi.endpoints.getVideo.initiate(id)返回的是RxJS Observable对象,而非标准Promise。直接用await无法获取到请求响应数据,这是代码失效的根本原因。此外,generateMetadata运行在Next.js的服务端(静态生成/SSR阶段),RTK Query的hook无法在此环境运行,需要用服务端兼容的请求方式。
解决方法
方法一:复用RTK Query的fetchBaseQuery(推荐)
如果你的rtkQueryApi是基于fetchBaseQuery创建的,可以直接调用底层的fetchBaseQuery发起请求,复用已配置的API域名、拦截器等逻辑:
export const generateMetadata = async ({ params }: Params) => { const { id } = params; // 调用RTK的baseQuery发起请求 const response = await rtkQueryApi.util.fetchBaseQuery({ url: `/pro/ru/block/get_selected_video?uid=${id}`, })(); // 处理错误情况 if ('error' in response) { return { title: '默认标题' }; } const data = response.data as Filters; return { title: data.title, }; };
方法二:将Observable转换为Promise
若要坚持使用initiate,可以借助RxJS的firstValueFrom将Observable转换为Promise,同时记得清理订阅避免内存泄漏:
import { firstValueFrom } from 'rxjs'; export const generateMetadata = async ({ params }: Params) => { const { id } = params; const queryObservable = pastEventsApi.endpoints.getVideo.initiate(id); try { const queryResult = await firstValueFrom(queryObservable); return { title: queryResult.data?.title, }; } catch (err) { return { title: '默认标题' }; } finally { // 取消订阅,避免服务端内存泄漏 queryObservable.unsubscribe(); } };
额外说明
- 服务端环境下,直接用
initiate无法保证数据被正确存入RTK store,若页面组件后续需要复用该数据,建议在组件中使用useQuery,RTK Query会自动识别缓存并复用,无需重复请求。
内容的提问来源于stack exchange,提问作者Глеб Кодрик
相关产品推荐
相关产品推荐

