如何让RTK Query像缓存200响应一样缓存404响应?
解决RTK Query缓存404错误的问题
这个问题我之前也碰到过!RTK Query默认确实不会缓存错误响应,尤其是404这类,导致同一个无效ID反复发起请求,组件每次都要等请求完成才显示回退内容,确实闹心。下面给你几个实用的解决方案:
方法一:用queryFn手动控制请求与缓存
如果你的查询逻辑不复杂,直接改用queryFn来定义查询,这样你可以完全掌控响应处理,包括把404状态存入缓存。
举个例子,假设你原本的查询是这样的:
getEntity: builder.query({ query: (id) => `/entities/${id}`, })
改成queryFn版本:
getEntity: builder.query({ queryFn: async (id, { queryFulfilled, dispatch }) => { try { const { data } = await queryFulfilled; return { data }; } catch (error) { // 检查是否是404错误 if (error.status === 404) { // 手动把这个ID的状态标记为404,存入缓存 dispatch( api.util.updateQueryData('getEntity', id, (draft) => { // 这里可以自定义存储的内容,比如标记为不存在 draft._isNotFound = true; }) ); // 返回错误,同时让组件能拿到这个标记 return { error: { status: 404, data: { _isNotFound: true } } }; } // 其他错误正常处理 return { error }; } }, // 设置缓存保留时间,确保404状态能保留 keepUnusedDataFor: 300, // 5分钟,可根据需求调整 })
这样下次再用同一个ID调用useGetEntityQuery时,RTK Query会直接返回缓存里的404状态,不会重复发起请求,组件就能立刻显示回退内容了。
方法二:利用onQueryStarted钩子缓存404状态
如果你不想改动原有的query定义,可以用onQueryStarted这个生命周期钩子,在请求完成后处理404并更新缓存:
getEntity: builder.query({ query: (id) => `/entities/${id}`, onQueryStarted: async (id, { queryFulfilled, dispatch }) => { try { await queryFulfilled; } catch (error) { if (error.status === 404) { // 更新缓存,标记该ID为不存在 dispatch( api.util.updateQueryData('getEntity', id, (draft) => { draft._isNotFound = true; }) ); } } }, keepUnusedDataFor: 300, })
然后在组件里使用时,检查返回的数据里的_isNotFound标记:
const { data, error, isLoading } = useGetEntityQuery(entityId); if (isLoading) return <Loading />; // 如果缓存里标记了不存在,直接显示回退内容 if (data?._isNotFound || error?.status === 404) { return <EntityNotFound />; } return <EntityDetails data={data} />;
方法三:自定义错误缓存逻辑(进阶)
如果你的应用里有很多这类需要缓存404的场景,可以考虑封装一个自定义的缓存middleware,或者利用RTK Query的cache配置扩展。不过这个方法相对复杂,适合需要全局统一处理的情况。
核心思路是监听查询的错误响应,当检测到404时,手动将该查询的缓存条目保留下来,而不是自动丢弃。
注意事项
- 记得设置
keepUnusedDataFor,确保缓存的404状态不会被立刻清理掉,时间可以根据业务需求调整。 - 如果你需要让用户手动刷新(比如用户觉得这个ID应该存在了),可以提供一个刷新按钮,调用
refetch方法强制重新发起请求。
内容的提问来源于stack exchange,提问作者marcvangend
相关产品推荐
相关产品推荐

