
在使用 RTK Query 时,若需根据条件(如用户未登录)跳过请求,直接访问 user.id 会导致运行时错误;正确做法是结合 skipToken 实现类型安全、逻辑清晰的条件请求。
在使用 rtk query 时,若需根据条件(如用户未登录)跳过请求,直接访问 `user.id` 会导致运行时错误;正确做法是结合 `skiptoken` 实现类型安全、逻辑清晰的条件请求。
RTK Query 提供了优雅处理“条件性请求”的机制,但关键在于:skip 选项仅控制是否发起网络请求,而传入的参数(如 user.id)仍会在组件渲染时被 JavaScript 执行——此时若 user 为 null 或 undefined,访问 .id 就会抛出 Cannot read properties of null (reading 'id') 错误。
✅ 正确方案:使用 skipToken
RTK Query 导出了专用的 skipToken(类型为 Symbol),它可作为 query 参数的“占位符”,当传入 skipToken 时,RTK Query 不仅跳过请求,还会跳过参数校验与序列化逻辑,从而彻底规避空值访问风险。
import { skipToken } from '@reduxjs/toolkit/query/react';
// ✅ 安全写法:user 存在才传 id,否则传 skipToken
const { data: carts = [] as ICart[], isFetching } =
api.useGetCartProductsQuery(user ? user.id : skipToken);
该方式具备以下优势:
- 类型安全:TypeScript 能识别 skipToken 类型,配合 query 参数定义(如 string | typeof skipToken)实现严格推导;
- 零副作用:不会触发任何请求、不会执行参数转换逻辑、不会产生额外 re-render;
- 可读性强:语义明确——“无有效参数即跳过”,比 skip: !user + 默认值更直观。
⚠️ 常见误区辨析
❌ 错误写法(仍会报错):
// 即使设置了 skip: true,user.id 仍在函数调用时求值!
api.useGetCartProductsQuery(user.id, { skip: !user }); // ❌ user 可能为 undefined
❌ 次优写法(冗余且易出错):
// 虽可运行,但需手动维护默认值,且无法利用 RTK Query 的 skipToken 优化机制
api.useGetCartProductsQuery(user?.id ?? '', { skip: !user }); // ❌ 空字符串可能触发无效请求或类型不匹配
? 最佳实践建议
- 始终将 skipToken 作为条件请求的首选方案;
- 在自定义 Hook 中封装逻辑时,可进一步抽象:
const useCartData = (user: User | null) => api.useGetCartProductsQuery(user?.id ?? skipToken);
- 若需响应式依赖(如 user.id 变化后重新请求),确保 user 是稳定引用(例如来自 useSelector 的 memoized state),避免因对象重创建导致不必要的 refetch。
通过 skipToken,你不仅能解决当前的运行时错误,还能写出更健壮、可维护的 RTK Query 集成代码。










