React Query 的缓存机制引发的问题

177 阅读2分钟

问题1

const { data: originalMyTrips } = useFetchTrips(data?.myTripIds ?? []);

当 ids 从 [] 变成 [198699] 时,data 会 undefinded,反之却不会

原因:

  1. 当 ids 从 [] 变成 [198699] 时:

    • 新的 queryKey 是 [QUERY_KEYS.trip, "[198699]"]
    • 这个 key 在缓存中不存在
    • 所以 React Query 会重新执行查询
    • 在查询完成前,data 是 undefined
  2. 当 ids 从 [198699] 变成 [] 时:

    • 新的 queryKey 是 [QUERY_KEYS.trip, "[]"]
    • 这个 key 在缓存中已经存在(因为之前已经查询过空数组)
    • 所以 React Query 会直接使用缓存的值 []
    • 不会出现 undefined 的状态

问题2

const { data: originalMyTrips } = useFetchTrips(data?.myTripIds ?? []); const { data: originalAllTrips } = useFetchTrips(data?.allTripIds ?? []);

当有2个请求时不会出现问题1的问题

- 当 ids 从 [] 变成 [198699] 时,originalMyTrips 不会变成 undefined
- 这是因为 allTripIds 总是存在,所以 originalAllTrips 的请求会先执行
- 当 originalAllTrips 的请求完成后,React Query 的缓存机制会更新
- 这时 originalMyTrips 的请求会使用更新后的缓存

问题3

const { data: originalMyTrips } = useFetchTrips(data?.myTripIds ?? [], Boolean(data)); const { data: originalMyTrips } = useFetchTrips(data?.myTripIds ?? [], true);

明明我的Boolean(data) 总是 true,但还是

原因分析:

当使用 方式1 useFetchTrips(data?.myTripIds ?? [], Boolean(data)) 时:

  1. 初始阶段 (data未加载)

    • data = undefined → Boolean(data) = false
    • 查询被禁用 (enabled: false)
    • originalMyTrips = undefined (默认状态)
  2. data加载完成 (myTripIds存在)

    • data = 有效值 → Boolean(data) = true
    • 查询启用 (enabled: true)
    • ids 从 [] 变为 [198699]
    • React Query 发现 queryKey 变化 (sortIds 从 "[]" → "[198699]")
    • 创建新查询实例,初始状态为 undefined
    • 发起网络请求 → 获取数据后更新为 [{…}]
  3. 当 ids 再次变为空数组

    • ids = [] → sortIds = "[]"
    • queryKey 再次变化 → 创建新查询实例
    • 由于 enabled: true 且 ids 为空,触发空数组查询
    • 若未显式处理空数组,可能返回 undefined

方式2 useFetchTrips(data?.myTripIds ?? [], true) 的行为:

  1. 始终启用查询 (enabled: true)
  2. 首次加载时 ids = [] (因 data 未加载)
    • 直接执行空数组查询 → 返回 []
  3. data加载后 ids 变为 [198699]
    • queryKey 变化 → 发起新查询
    • 保留旧数据 ([]) 直到新查询完成
  4. 没有 enabled 状态切换
    • 避免查询实例重建导致的 undefined 状态
graph TD
A[组件挂载] --> B{查询enabled?}
B -->|方式一:否| C[等待data加载]
B -->|方式二:是| D[立即执行空数组查询]
C --> E[data加载完成]
E --> F[执行有效ids查询]
D --> G[缓存空数组结果]
F --> H[缓存有效结果]
G --> I[后续ids变化触发新查询]