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

如何基于Redux Toolkit轮询场景管理查询加载状态?

解决RTK Query轮询时区分加载状态的问题

我有一个基于Redux Toolkit (RTK) Query的React应用,调用REST API时需要显示加载状态,同时每15秒轮询一次接口获取更新数据——因为响应里部分字段会频繁变化,但渲染加载区域的UI数据不会变。

当前用isFetching控制加载状态,问题是轮询时isFetching也会变为true,导致轮询过程中也显示加载动画。我希望仅在初始加载、或者请求参数(比如orgId)变更时显示加载状态,轮询时不触发该加载状态。

尝试过用isLoading替代,但参数变更触发重新请求时,isLoading不会生效,无法满足需求。


最小复现代码

FooComponent.tsx

import { useGetFooDataQuery } from '../app/services/foo';
import { CircularProgress } from '@mui/material';
const POLLING_INTERVAL = 20000;
const FooComponent = ({ orgId }: { orgId: string }) => {
  const {
    data: foo,
    isLoading: isLoading,
    isFetching: isFetching,
  } = useGetFooDataQuery(
    {
      org_id: orgId,
    },
    {
      pollingInterval: POLLING_INTERVAL,
      refetchOnMountOrArgChange: true,
    },
  );
  const { data_that_only_changes_when_org_id_changes, polled_data_prone_to_change } = foo ?? {};

  return (
    <div>
      <div>{isFetching ? <CircularProgress /> : data_that_only_changes_when_org_id_changes}</div> {/* 期望仅初始加载或org_id变更时显示加载 */}
      <div>{isFetching ? <CircularProgress /> : polled_data_prone_to_change}</div> {/* 每次请求(含轮询)都显示加载 */}
    </div>
  );
};

export default FooComponent;

foo.ts

import { api } from './api';

type GetFooDataQueryParams = {
  org_id: string;
};

type FooData = {
  data_that_only_changes_when_org_id_changes: number;
  polled_data_prone_to_change: number;
};

export const fooApi = api.injectEndpoints({
  endpoints: (builder) => ({
    getFooData: builder.query<FooData, GetFooDataQueryParams>({
      query: (args) => {
        const body = {
          org_id: args.org_id,
        };
        return {
          url: 'data/foo',
          method: 'GET',
          body: body,
        };
      },
    }),
  }),
});

export const { useGetFooDataQuery } = fooApi;

api.ts

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { RootState } from '../store'; 
import { getApiURL } from '../../utilities/url';

const baseQuery = fetchBaseQuery({
  baseUrl: getApiURL([]),
  prepareHeaders: (headers, { getState }) => {
    const token = (getState() as RootState).auth.token;
    if (token) {
      headers.set('Authorization', `Bearer ${token}`);
    }
    headers.set('Accept', 'application/json');
    headers.set('Content-Type', 'application/json');
    return headers;
  },
});


export const api = createApi({
  
  reducerPath: 'splitApi',
  baseQuery: baseQuery,
  endpoints: () => ({}),
});

export const enhancedApi = api.enhanceEndpoints({
  endpoints: () => ({
    getPost: () => 'test',
  }),
});

临时解决方案

通过追踪请求触发原因(参数变更/轮询),控制加载状态:

import { useEffect, useState } from 'react';
import { useGetFooDataQuery } from '../services/fooService';
import { CircularProgress } from '@mui/material';
const POLLING_INTERVAL = 20000;

const FooComponent = ({ orgId }: { orgId: string }) => {
  const [mountOrQueryArgChange, setMountOrQueryArgChange] = useState<boolean>(false);

  const { data: foo, isFetching: isFetching } = useGetFooDataQuery(
    {
      org_id: orgId,
    },
    {
      pollingInterval: POLLING_INTERVAL,
      refetchOnMountOrArgChange: true,
    },
  );

  useEffect(() => {
    setMountOrQueryArgChange(true);
  }, [orgId]);

  useEffect(() => {
    if (!isFetching) setMountOrQueryArgChange(false);
  }, [isFetching]);

  const { data_that_only_changes_when_org_id_changes, polled_data_prone_to_change } = foo ?? {};

  return (
    <div>
      {/* 仅初始加载或org_id变更触发请求时显示加载 */}
      <div>
        {mountOrQueryArgChange && isFetching ? <CircularProgress /> : data_that_only_changes_when_org_id_changes}
      </div>

      {/* 每次请求(含轮询)都显示加载 */}
      <div>{isFetching ? <CircularProgress /> : polled_data_prone_to_change}</div>
    </div>
  );
};

export default FooComponent;

更优解决方案:拆分查询

将静态数据和动态数据拆分为两个独立的RTK Query端点,分别控制加载逻辑和轮询策略,无需额外状态追踪:

1. 修改API端点(foo.ts)

import { api } from './api';

type GetFooDataQueryParams = {
  org_id: string;
};

type FooData = {
  data_that_only_changes_when_org_id_changes: number;
  polled_data_prone_to_change: number;
};

export const fooApi = api.injectEndpoints({
  endpoints: (builder) => ({
    // 静态数据:仅在初始加载/参数变更时请求,不轮询
    getStaticFooData: builder.query<{data_that_only_changes_when_org_id_changes: number}, GetFooDataQueryParams>({
      query: (args) => ({
        url: 'data/foo',
        method: 'GET',
        body: { org_id: args.org_id }
      }),
      transformResponse: (response: FooData) => ({
        data_that_only_changes_when_org_id_changes: response.data_that_only_changes_when_org_id_changes
      })
    }),
    // 动态数据:启用轮询,实时获取更新
    getPolledFooData: builder.query<{polled_data_prone_to_change: number}, GetFooDataQueryParams>({
      query: (args) => ({
        url: 'data/foo',
        method: 'GET',
        body: { org_id: args.org_id }
      }),
      transformResponse: (response: FooData) => ({
        polled_data_prone_to_change: response.polled_data_prone_to_change
      })
    }),
  }),
});

export const { useGetStaticFooDataQuery, useGetPolledFooDataQuery } = fooApi;

2. 修改组件逻辑(FooComponent.tsx)

import { useGetStaticFooDataQuery, useGetPolledFooDataQuery } from '../app/services/foo';
import { CircularProgress } from '@mui/material';
const POLLING_INTERVAL = 20000;

const FooComponent = ({ orgId }: { orgId: string }) => {
  // 静态数据:用isLoading控制加载(仅初始/参数变更时显示)
  const { 
    data: staticData, 
    isLoading: isStaticLoading 
  } = useGetStaticFooDataQuery({ org_id: orgId });

  // 动态数据:用isFetching控制加载(所有请求含轮询都显示)
  const { 
    data: polledData, 
    isFetching: isPolledFetching 
  } = useGetPolledFooDataQuery(
    { org_id: orgId },
    { pollingInterval: POLLING_INTERVAL }
  );

  return (
    <div>
      <div>
        {isStaticLoading ? <CircularProgress /> : staticData?.data_that_only_changes_when_org_id_changes}
      </div>
      <div>
        {isPolledFetching ? <CircularProgress /> : polledData?.polled_data_prone_to_change}
      </div>
    </div>
  );
};

export default FooComponent;

这种方案逻辑更清晰,完全利用RTK Query自身的状态管理能力,避免了手动追踪请求触发原因的复杂度。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 04:29:51