如何基于Redux单变量实现多API请求的独立加载指示器
Great question—tracking individual loading states for each API call is crucial as your app scales, and moving away from a single isLoading flag is the right move. Here's how to implement this with minimal changes to your existing Redux setup:
Step 1: Update the Redux State Structure
First, replace the single isLoading boolean with an object that maps unique request identifiers to their loading status. This lets us track each request independently:
// reducer.js export const initialState = { isAuth: false, loadingRequests: {}, // Key: request identifier, Value: boolean (loading status) btnDisable: false, isError: null }; export default function(state = initialState, action) { switch (action.type) { case API_REQUEST: return { ...state, loadingRequests: { ...state.loadingRequests, [action.payload.requestKey]: true // Mark this request as loading } }; case API_SUCCESS: return { ...state, loadingRequests: { ...state.loadingRequests, [action.payload.requestKey]: false // Mark this request as complete }, isError: null }; case API_FAILURE: return { ...state, loadingRequests: { ...state.loadingRequests, [action.payload.requestKey]: false // Mark this request as failed }, isError: action.payload.error }; case GETLIST: return { ...state, list: action.payload }; default: return state; } }
Step 2: Modify Action Creators to Include Request Keys
Update your action creators to pass a unique requestKey with each API action. This key will link the loading state to the specific request:
// action.js export const API_REQUEST = 'API_REQUEST'; export const API_SUCCESS = 'API_SUCCESS'; export const API_FAILURE = 'API_FAILURE'; export const GETLIST = 'GETLIST'; // Reusable helper actions for API lifecycle const apiRequest = (requestKey) => ({ type: API_REQUEST, payload: { requestKey } }); const apiSuccess = (requestKey) => ({ type: API_SUCCESS, payload: { requestKey } }); const apiFailure = (requestKey, error) => ({ type: API_FAILURE, payload: { requestKey, error } }); // Example action for your existing list request export const getListRequest = () => { return (dispatch) => { const requestKey = 'dashboard_getList'; // Unique key for this request dispatch(apiRequest(requestKey)); API.anygetcall() .then((res) => { dispatch(apiSuccess(requestKey)); dispatch({ type: GETLIST, payload: res }); }) .catch((err) => { dispatch(apiFailure(requestKey, err)); }); }; }; // Example of another request (for a different widget) export const getUserProfileRequest = () => { return (dispatch) => { const requestKey = 'dashboard_userProfile'; dispatch(apiRequest(requestKey)); API.getUserProfile() .then((res) => { dispatch(apiSuccess(requestKey)); dispatch({ type: GET_USER_PROFILE, payload: res }); }) .catch((err) => { dispatch(apiFailure(requestKey, err)); }); }; };
Step 3: Use the Loading State in Components
In each widget/component, check the loading status for its specific request key to show the loading indicator:
// DashboardWidget.js (example component) import { connect } from 'react-redux'; import { getListRequest } from './actions'; const DashboardListWidget = ({ isLoading, list, getListRequest }) => { // Fetch data on mount useEffect(() => { getListRequest(); }, [getListRequest]); if (isLoading) { return <div className="widget-loader">Loading list...</div>; } return ( <div className="dashboard-widget"> {list.map(item => <div key={item.id}>{item.name}</div>)} </div> ); }; const mapStateToProps = (state) => ({ // Check the specific request key for this widget isLoading: state.loadingRequests['dashboard_getList'] || false, list: state.list || [] }); export default connect(mapStateToProps, { getListRequest })(DashboardListWidget);
Key Workflow Adjustments
- Unique Request Keys: Assign a meaningful, unique key to every API call (e.g.,
dashboard_userProfile,settings_updatePreferences). This ensures no overlap in loading state tracking. - Reusable API Helpers: The
apiRequest,apiSuccess, andapiFailurehelpers eliminate duplicate code across action creators. - Component-Specific Loading Checks: Each component only cares about its own request key, so loading states don't bleed between widgets.
- Scalability: As you add more API calls, you just add new request keys—no need to modify the reducer or add new
isLoadingflags.
内容的提问来源于stack exchange,提问作者tapan dave

