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

为何useQuery为每个Observer触发?如何按需展示Toast?

React Query 全局回调过滤与类型处理问题

现有实现

我使用useQuery的onSuccess回调验证API调用是否返回数据,若未返回数据则展示“未找到结果”的Toast。

遇到的问题

Toast会为每个Observer重复渲染,这是钩子为每个Observer执行的预期行为,但不符合需求。

核心需求

通过全局回调避免重复渲染Toast,需按请求的queryKey过滤,仅当queryKey为“search”且无返回数据时展示Toast,现有代码框架如下:

const queryClient = new QueryClient({
  queryCache: new QueryCache({
    onSuccess: (error) =>
      // how to filter here the request to show the toast
      // according to the queryKey and if no data is retrieved from the backend
  }),
})

其他问题

  1. 还有哪些方法可避免该行为(避免在每个Observer中执行代码)?
  2. 使用Axios作为请求客户端时,如何处理错误或成功回调中的TS类型?

解决方案

1. 全局QueryCache的onSuccess回调过滤实现

首先纠正一个小问题:QueryCache的onSuccess回调参数是data、query,不是error。你可以通过query.queryKey判断目标请求,同时检查返回数据是否为空:

const queryClient = new QueryClient({
  queryCache: new QueryCache({
    onSuccess: (data, query) => {
      // 过滤queryKey为"search"的请求,同时判断数据是否为空
      if (query.queryKey[0] === "search" && (!data || Object.keys(data).length === 0)) {
        // 展示"未找到结果"的Toast
        showToast("未找到结果");
      }
    },
  }),
});

2. 避免重复执行的其他方法

  • 封装自定义Hook:写一个专属的useSearchQuery,把Toast逻辑放在这个Hook里,确保每个搜索请求只执行一次逻辑,避免多个Observer重复触发:
    const useSearchQuery = (searchParams) => {
      return useQuery({
        queryKey: ["search", searchParams],
        queryFn: () => axios.get("/api/search", { params: searchParams }),
        onSuccess: (data) => {
          if (!data || Object.keys(data).length === 0) {
            showToast("未找到结果");
          }
        },
        // 设置staleTime减少重复请求触发回调的次数
        staleTime: 5000,
      });
    };
    
  • 手动触发全局检查:使用queryClient.invalidateQueries时,结合自定义逻辑只在搜索请求完成后触发一次Toast,不依赖Observer回调。
  • 全局Context管理状态:把搜索结果的空状态存入全局Context,只在状态变化时触发一次Toast,避免重复渲染。

3. Axios结合TypeScript的类型处理

成功回调类型定义

为Axios响应定义接口,明确返回数据结构,让TS自动推断类型:

interface SearchResponse {
  results: Array<{ id: string; name: string }>;
  total: number;
}

// 在queryFn中指定响应类型
const queryFn = async () => {
  const response = await axios.get<SearchResponse>("/api/search");
  return response.data;
};

此时onSuccess中的data会自动匹配SearchResponse类型,无需额外断言。

错误回调类型处理

用AxiosError捕获错误,结合自定义后端错误结构:

import { AxiosError } from "axios";

// 自定义后端返回的错误格式
interface ApiError {
  message: string;
  code: number;
}

// 在useQuery的onError中处理
onError: (error) => {
  const axiosError = error as AxiosError<ApiError>;
  if (axiosError.response?.data) {
    console.error(axiosError.response.data.message);
  }
};

内容的提问来源于stack exchange,提问作者Cristian Flórez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 14:15:41