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

React Query:如何为3个子组件统一显示加载Spinner?

实现单一加载Spinner的两种方案

方案一:利用React Query的全局查询状态

如果你的useSurveyInfo和useResponses是基于React Query封装的自定义Hook,可以直接借助React Query的全局状态能力,无需修改子组件代码就能实现单一Spinner。

操作步骤:

  1. 确认自定义Hook的查询键
    确保两个Hook内部使用了可识别的唯一查询键,示例如下:

    // useSurveyInfo 示例
    export const useSurveyInfo = (id) => {
      return useQuery({
        queryKey: ['survey-info', id], // 核心:绑定查询唯一标识
        queryFn: () => fetchSurveyInfo(id),
      });
    };
    
    // useResponses 示例
    export const useResponses = (id) => {
      return useQuery({
        queryKey: ['responses', id], // 核心:绑定查询唯一标识
        queryFn: () => fetchResponses(id),
      });
    };
    
  2. 在父组件中监听加载状态
    使用useIsFetching钩子监听目标查询的加载状态,判断是否显示Spinner:

    import { useIsFetching } from '@tanstack/react-query';
    
    const ParentComponent = ({ id }) => {
      // 监听两个查询的正在加载请求数量
      const surveyLoadingCount = useIsFetching({ queryKey: ['survey-info', id] });
      const responsesLoadingCount = useIsFetching({ queryKey: ['responses', id] });
      const showSpinner = surveyLoadingCount > 0 || responsesLoadingCount > 0;
    
      return (
        <>
          {showSpinner && <div className="loading-spinner">加载中...</div>}
          <ChildComponent1 id={id} />
          <ChildComponent2 id={id} />
          <ChildComponent3 id={id} />
        </>
      );
    };
    

原理说明:

React Query会全局跟踪所有查询的请求状态,useIsFetching返回匹配指定查询键的正在进行的请求数量。只要有一个请求在加载,就会返回大于0的数值,此时即可触发Spinner显示。同时React Query的缓存机制会避免多个组件调用同一查询时重复发起请求,不会影响性能。


方案二:自定义Context管理加载状态

如果你的自定义Hook是自行实现的(不依赖React Query),可以通过React Context统一管理所有子组件的加载状态,彻底避免prop drilling。

操作步骤:

  1. 创建加载状态Context

    import { createContext, useContext, useState } from 'react';
    
    const LoadingContext = createContext();
    
    export const LoadingProvider = ({ children }) => {
      // 用计数器跟踪加载中的请求数量
      const [loadingCount, setLoadingCount] = useState(0);
    
      const startLoading = () => setLoadingCount(prev => prev + 1);
      const endLoading = () => setLoadingCount(prev => Math.max(prev - 1, 0));
    
      return (
        <LoadingContext.Provider 
          value={{ 
            startLoading, 
            endLoading, 
            isLoading: loadingCount > 0 
          }}
        >
          {children}
        </LoadingContext.Provider>
      );
    };
    
    // 自定义Hook简化Context调用
    export const useLoading = () => useContext(LoadingContext);
    
  2. 修改自定义Hook,同步全局加载状态
    在useSurveyInfo和useResponses中,调用Context方法更新全局加载状态:

    export const useSurveyInfo = (id) => {
      const { startLoading, endLoading } = useLoading();
      const [data, setData] = useState(null);
      const [isLoading, setIsLoading] = useState(false);
      const [isError, setIsError] = useState(false);
    
      useEffect(() => {
        const fetchData = async () => {
          setIsLoading(true);
          startLoading();
          try {
            const res = await fetch(`/api/survey/${id}`);
            const result = await res.json();
            setData(result);
            setIsError(false);
          } catch (err) {
            setIsError(true);
          } finally {
            setIsLoading(false);
            endLoading();
          }
        };
    
        fetchData();
      }, [id, startLoading, endLoading]);
    
      return { data, isLoading, isError };
    };
    

    按照相同逻辑修改useResponses Hook。

  3. 在父组件中使用Spinner
    确保父组件被LoadingProvider包裹(可在根组件统一包裹),然后获取全局加载状态:

    import { useLoading } from './LoadingContext';
    
    const ParentComponent = ({ id }) => {
      const { isLoading } = useLoading();
    
      return (
        <>
          {isLoading && <div className="loading-spinner">加载中...</div>}
          <ChildComponent1 id={id} />
          <ChildComponent2 id={id} />
          <ChildComponent3 id={id} />
        </>
      );
    };
    

原理说明:

通过Context维护一个全局加载计数器,每个子组件发起请求时递增计数器,请求结束后递减计数器。只要计数器大于0,就显示Spinner。这种方式完全自定义,不依赖第三方库。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:50:20