React应用如何实现全局单Loader Reducer(无需单独编写动作)
实现全局加载器的Redux解决方案(无需单独编写加载器Action)
这个需求非常常见,结合你已有的Redux+redux-pack技术栈,我们可以直接利用redux-pack处理Promise时自动生成的生命周期元数据,来实现一个全局单Reducer管理加载状态,完全不需要额外编写加载器相关的Action。
核心思路
redux-pack在处理带promise字段的Action时,会自动分发包含meta.status的Action,状态包括START(请求开始)、SUCCESS/FAILURE/COMPLETE(请求结束)。我们只需要写一个全局Reducer,监听这些带有redux-pack标记的Action,根据状态更新加载计数即可。
步骤1:编写全局Loading Reducer
这个Reducer会跟踪当前活跃的API请求数量,只要有请求在进行,就显示加载器;所有请求完成后自动隐藏。
import { START, SUCCESS, FAILURE, COMPLETE } from 'redux-pack'; const initialState = { activeRequests: 0, // 跟踪活跃请求数 }; const loadingReducer = (state = initialState, action) => { // 只处理redux-pack管理的Action(带有meta.promise标记) if (!action.meta?.promise) { return state; } switch (action.meta.status) { case START: // 请求开始,活跃数+1 return { ...state, activeRequests: state.activeRequests + 1, }; case SUCCESS: case FAILURE: case COMPLETE: // 请求结束,活跃数-1(确保不会变成负数) return { ...state, activeRequests: Math.max(state.activeRequests - 1, 0), }; default: return state; } }; export default loadingReducer;
如果需要跟踪单个请求的加载状态(比如某个按钮点击后的加载),可以修改Reducer为按Action Type存储状态:
import { START, SUCCESS, FAILURE, COMPLETE } from 'redux-pack'; const initialState = { byActionType: {}, // 按Action Type存储每个请求的加载状态 }; const loadingReducer = (state = initialState, action) => { if (!action.meta?.promise) return state; const actionType = action.type; switch (action.meta.status) { case START: return { ...state, byActionType: { ...state.byActionType, [actionType]: true }, }; case SUCCESS: case FAILURE: case COMPLETE: return { ...state, byActionType: { ...state.byActionType, [actionType]: false }, }; default: return state; } };
步骤2:合并到Root Reducer
将这个全局Loading Reducer合并到你的根Reducer中:
import { combineReducers } from 'redux'; import loadingReducer from './loadingReducer'; // 导入你的其他业务Reducer import userReducer from './userReducer'; import postReducer from './postReducer'; const rootReducer = combineReducers({ loading: loadingReducer, user: userReducer, post: postReducer, // ...其他业务Reducer }); export default rootReducer;
步骤3:实现全局加载器组件
创建一个全局加载器组件,通过Redux获取加载状态并渲染:
import React from 'react'; import { useSelector } from 'react-redux'; const GlobalLoader = () => { // 判断是否有活跃请求 const isLoading = useSelector(state => state.loading.activeRequests > 0); if (!isLoading) return null; return ( <div style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, backgroundColor: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 9999, }}> <div style={{ fontSize: '2rem', color: 'white' }}>加载中...</div> </div> ); }; export default GlobalLoader;
然后在你的App根组件中引入它:
import React from 'react'; import GlobalLoader from './GlobalLoader'; // 其他路由/组件 function App() { return ( <div className="App"> <GlobalLoader /> {/* 你的应用内容:导航、路由等 */} </div> ); } export default App;
步骤4:确保你的API Action正确使用redux-pack
只要你的业务Action是按照redux-pack的规范编写的(包含promise字段),这个方案就会自动生效。示例Action:
import { FETCH_USER } from './actionTypes'; import api from '../api'; // redux-pack会自动处理这个promise,分发生命周期Action export const fetchUser = (userId) => ({ type: FETCH_USER, promise: api.getUser(userId), });
内容的提问来源于stack exchange,提问作者Abin Thaha Azees




