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

React全局加载器实现:API调用/状态变更时自动显示全屏加载

全局自动加载控制方案

方案一:Redux Toolkit 全局 Async Thunk 监听(适配多store架构)

利用Redux中间件自动监听所有异步action的状态,维护全局加载计数,无需手动在每个thunk里设置loading状态。

步骤1:创建全局Loading Slice

// src/store/loadingSlice.js
import { createSlice } from '@reduxjs/toolkit';

const initialState = {
  activeRequests: 0,
};

const loadingSlice = createSlice({
  name: 'loading',
  initialState,
  reducers: {
    incrementLoading: (state) => {
      state.activeRequests += 1;
    },
    decrementLoading: (state) => {
      state.activeRequests = Math.max(0, state.activeRequests - 1);
    },
  },
});

export const { incrementLoading, decrementLoading } = loadingSlice.actions;
export default loadingSlice.reducer;

步骤2:编写自定义Redux中间件

自动识别createAsyncThunk生成的pending/fulfilled/rejected action,更新加载计数:

// src/store/middleware/loadingMiddleware.js
import { incrementLoading, decrementLoading } from '../loadingSlice';

export const loadingMiddleware = (store) => (next) => (action) => {
  if (action.type.endsWith('/pending')) {
    store.dispatch(incrementLoading());
  }
  if (action.type.endsWith('/fulfilled') || action.type.endsWith('/rejected')) {
    store.dispatch(decrementLoading());
  }
  return next(action);
};

步骤3:将Slice和中间件加入全局Store

// src/store/index.js
import { configureStore } from '@reduxjs/toolkit';
import loadingReducer from './loadingSlice';
import { loadingMiddleware } from './middleware/loadingMiddleware';
// 导入你的其他组件slice
import userReducer from '../components/User/store/userSlice';
import productReducer from '../components/Product/store/productSlice';

export const store = configureStore({
  reducer: {
    loading: loadingReducer,
    user: userReducer,
    product: productReducer,
    // 其他组件的reducer...
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(loadingMiddleware),
});

步骤4:全局加载器组件

在App根组件中根据activeRequests控制加载器显示:

// src/App.js
import { useSelector } from 'react-redux';
import FullScreenLoader from './components/FullScreenLoader';

function App() {
  const activeRequests = useSelector((state) => state.loading.activeRequests);

  return (
    <div className="App">
      {activeRequests > 0 && <FullScreenLoader />}
      {/* 你的路由和其他组件 */}
    </div>
  );
}

export default App;

方案二:Axios拦截器结合全局状态(解决拦截器无法设置加载状态问题)

直接在Axios拦截器中操作全局Redux状态,关键是确保Axios实例能获取到初始化后的store。

步骤1:配置Axios实例并关联Store

// src/utils/axiosInstance.js
import axios from 'axios';
import { store } from '../store';
import { incrementLoading, decrementLoading } from '../store/loadingSlice';

const axiosInstance = axios.create({
  baseURL: 'https://your-api-base-url.com',
});

// 请求拦截器:发起请求时增加加载计数
axiosInstance.interceptors.request.use(
  (config) => {
    store.dispatch(incrementLoading());
    return config;
  },
  (error) => {
    store.dispatch(decrementLoading());
    return Promise.reject(error);
  }
);

// 响应拦截器:请求完成(成功/失败)时减少加载计数
axiosInstance.interceptors.response.use(
  (response) => {
    store.dispatch(decrementLoading());
    return response;
  },
  (error) => {
    store.dispatch(decrementLoading());
    return Promise.reject(error);
  }
);

export default axiosInstance;

步骤2:全局加载器组件

直接复用方案一中的App.js代码,通过activeRequests状态控制加载器显示。

方案三:利用React Query的全局加载状态(若项目可引入)

React Query内置全局加载状态管理,无需手动维护计数:

步骤1:配置React Query

// src/store/queryClient.js
import { QueryClient } from '@tanstack/react-query';

export const queryClient = new QueryClient();

步骤2:在根组件中使用全局加载状态

// src/App.js
import { QueryClientProvider, useIsFetching } from '@tanstack/react-query';
import { queryClient } from './store/queryClient';
import FullScreenLoader from './components/FullScreenLoader';

function AppContent() {
  const isFetching = useIsFetching();

  return (
    <div className="App">
      {isFetching > 0 && <FullScreenLoader />}
      {/* 你的路由和其他组件 */}
    </div>
  );
}

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AppContent />
    </QueryClientProvider>
  );
}

export default App;

关键注意事项

  • 方案一、二的计数逻辑支持并发请求,只有所有请求完成后才关闭加载器,避免闪烁。
  • 方案一要求所有异步操作通过createAsyncThunk创建,否则中间件无法监听。
  • 方案二需确保Axios实例在store初始化完成后再导入,避免store为undefined。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 12:28:30