You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Query中useQuery查询函数随数据更新失效问题求助

问题:React Query v5中useQuery查询函数无法获取最新的deck值

在使用@tanstack/react-query v5.10.0时,当OfflineContext中的deck值从初始对象变为null后,调用queryClient.invalidateQueries触发查询重取,useQuery的查询函数仍使用旧的deck值,而非最新的null。已尝试用useCallback包裹查询函数,但问题依旧。需求是保持查询键不变的前提下,让查询函数能获取最新的deck值。

原代码片段

import { request } from "../utils/fetch-utils";
import { useQuery } from "@tanstack/react-query";
import { CustomError } from "../utils/customError";
import { useCallback, useContext } from "react";
import { OfflineContext } from "../context/OfflineContext";
import { DeckTypeForSearch } from "../types/types";

type SuccessResponseType = {
  title: string;
  cards: { title: string; note: string; cardId: string; _id: string }[];
  _id: string;
};

const getCards = async (
  _id: string,
  deck: DeckTypeForSearch | null
): Promise<SuccessResponseType | null> => {
  if (!deck) {
    try {
      const data = await request.get(`/cards/${_id}`);
      return data?.data;
    } catch (error) {
      if (error instanceof CustomError) {
        throw new CustomError(error?.message, error?.statusCode);
      } else {
        throw new CustomError("Something went wrong!", 503);
      }
    }
  } else if (deck) {
    return { title: deck.title, cards: deck.cards, _id: deck.deck_id };
  }

  return null;
};

const useGetCards = (deck_id: string) => {
  const { deck } = useContext(OfflineContext);

  const queryKey = ["cards", deck_id];
  const getDataCallbackFunction = useCallback(() => {
    return getCards(deck_id, deck);
  }, [deck, deck_id]);

  return useQuery({
    queryKey: queryKey,
    queryFn: () => {
      return getDataCallbackFunction();
    },
    refetchOnWindowFocus: false,
    refetchOnReconnect: true,
    retry: 0,
    gcTime: 10800000, 
  });
};

export default useGetCards;

触发重取的代码

queryClient.invalidateQueries({
  queryKey: ["cards", mutationData.deck_id],
});

原因分析

问题出在闭包捕获:useCallback生成的函数会捕获创建时的deck值,即使后续deck更新,已经缓存的查询函数闭包仍持有旧值。当调用invalidateQueries时,React Query会复用之前的查询函数闭包,导致无法获取最新的deck状态。

解决方案

使用useRef跟踪最新的deck值,让查询函数每次执行时都能访问到当前最新的状态,无需修改查询键:

import { request } from "../utils/fetch-utils";
import { useQuery } from "@tanstack/react-query";
import { CustomError } from "../utils/customError";
import { useContext, useRef, useEffect } from "react";
import { OfflineContext } from "../context/OfflineContext";
import { DeckTypeForSearch } from "../types/types";

type SuccessResponseType = {
  title: string;
  cards: { title: string; note: string; cardId: string; _id: string }[];
  _id: string;
};

const getCards = async (
  _id: string,
  deck: DeckTypeForSearch | null
): Promise<SuccessResponseType | null> => {
  if (!deck) {
    try {
      const data = await request.get(`/cards/${_id}`);
      return data?.data;
    } catch (error) {
      if (error instanceof CustomError) {
        throw new CustomError(error?.message, error?.statusCode);
      } else {
        throw new CustomError("Something went wrong!", 503);
      }
    }
  } else if (deck) {
    return { title: deck.title, cards: deck.cards, _id: deck.deck_id };
  }

  return null;
};

const useGetCards = (deck_id: string) => {
  const { deck } = useContext(OfflineContext);
  // 用ref跟踪最新的deck值
  const deckRef = useRef<DeckTypeForSearch | null>(deck);

  // 当deck更新时,同步更新ref的current值
  useEffect(() => {
    deckRef.current = deck;
  }, [deck]);

  const queryKey = ["cards", deck_id];

  return useQuery({
    queryKey: queryKey,
    // 每次执行queryFn时,取ref.current的最新deck值
    queryFn: () => {
      return getCards(deck_id, deckRef.current);
    },
    refetchOnWindowFocus: false,
    refetchOnReconnect: true,
    retry: 0,
    gcTime: 10800000, 
  });
};

export default useGetCards;

方案说明

  1. useRef跟踪状态:deckRef会始终保存最新的deck值,不受闭包捕获的影响。
  2. useEffect同步更新:当deck状态变化时,自动更新deckRef.current,确保查询函数总能拿到最新值。
  3. 无需修改查询键:保持原有的["cards", deck_id]查询键,满足需求。

当再次调用queryClient.invalidateQueries时,查询函数会使用deckRef.current的最新值(即null),从而触发正确的网络请求。


内容的提问来源于stack exchange,提问作者Max Vhanamane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 22:27:53