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
相关产品推荐
相关产品推荐

