RTK:存在最新请求时阻止旧请求的matchFulfilled执行
针对RTK Query Lazy Query请求覆盖问题的解决方案
1. 开启cancelPrevious自动中止旧请求
RTK Query的useLazyQuery内置了cancelPrevious配置,开启后每次触发新请求时会自动取消之前未完成的同类型请求,直接解决旧请求覆盖新数据的问题:
const [triggerGetCardData] = useLazyQuery(getCardData, { cancelPrevious: true }); // 选中卡片时触发请求 triggerGetCardData(id);
开启后,未完成的旧请求会被直接中止,不会执行后续的matchFulfilled逻辑,完全匹配你的需求。
2. 自定义QueryFn结合AbortController手动控制
如果cancelPrevious不适用你的场景,可以在自定义queryFn中利用AbortController手动管理请求:
先修改API切片中的getCardData:
export const apiSlice = createApi({ reducerPath: 'api', baseQuery: fetchBaseQuery({ baseUrl: '/' }), endpoints: (builder) => ({ getCardData: builder.query({ queryFn: async (id, { signal }) => { try { const res = await fetch(`/api/cards/${id}`, { signal }); const data = await res.json(); return { data }; } catch (err) { if (err.name === 'AbortError') { // 请求被中止,直接返回取消状态 return { error: { status: 'CANCELED', message: 'Request aborted' } }; } return { error: { status: res?.status, message: err.message } }; } }, }), }), });
然后在组件中手动保存控制器实例,触发新请求前中止旧请求:
let abortController = null; const [triggerGetCardData] = useLazyQuery(getCardData); const handleCardSelect = (id) => { // 中止旧请求 abortController?.abort(); // 创建新控制器 abortController = new AbortController(); // 传入signal触发请求 triggerGetCardData(id, { signal: abortController.signal }); };
3. 响应阶段过滤:只处理最新请求结果
如果无法中止请求,退而求其次可以在响应环节只处理最新请求的结果,不需要到处传递ID:
let latestRequestId = null; const [triggerGetCardData] = useLazyQuery(getCardData, { onQueryStarted: (id) => { // 记录当前触发的请求ID latestRequestId = id; }, matchFulfilled: (action) => { // 仅当响应ID与最新请求ID一致时才更新地图 if (action.meta.arg === latestRequestId) { updateMapData(action.payload); } }, });
这个方案不需要修改请求发送逻辑,仅在结果处理时做判断,改造成本较低,适合前端计算类无ID请求的场景。
内容的提问来源于stack exchange,提问作者Berci
相关产品推荐
相关产品推荐

