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

如何在基于Axios与Redux-Promise的Redux应用中实现加载条(无需Redux-Thunk)

Absolutely! You don’t have to tie yourself to Redux-Thunk to add loading bars to your Redux app—there’s a much simpler approach using a flat state structure and plain Redux + Axios helper functions that avoids extra middleware complexity. Here’s how to implement it:

1. Define a Flat Loading State

Start with a straightforward, flat state object to track loading status for each API endpoint (or a global count for a single loading bar). For per-endpoint tracking:

// redux/initialState.js
const initialState = {
  // Flat object mapping API endpoints to loading status
  loading: {
    fetchUser: false,
    getPosts: false,
    updateProfile: false
  },
  // Your existing state properties
  user: null,
  posts: [],
  error: null
};
2. Create Minimal Action Types & Reducer

You only need two simple actions to toggle loading states. The reducer will update the flat loading object directly:

// redux/actions.js
export const startLoading = (endpoint) => ({
  type: 'START_LOADING',
  payload: endpoint
});

export const stopLoading = (endpoint) => ({
  type: 'STOP_LOADING',
  payload: endpoint
});

// redux/reducer.js
const appReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'START_LOADING':
      return {
        ...state,
        loading: {
          ...state.loading,
          [action.payload]: true
        }
      };
    case 'STOP_LOADING':
      return {
        ...state,
        loading: {
          ...state.loading,
          [action.payload]: false
        }
      };
    // Handle your existing API success/error actions here
    case 'FETCH_USER_SUCCESS':
      return { ...state, user: action.payload };
    default:
      return state;
  }
};
3. Wrap Axios Calls with Loading Helpers

Create a reusable utility function to wrap your Axios requests. This function will dispatch the loading actions before and after the call—no thunk required, just pass dispatch directly from your component:

// api/helpers.js
import axios from 'axios';
import { startLoading, stopLoading } from '../redux/actions';

export const apiCallWithLoading = async (dispatch, endpoint, axiosConfig) => {
  // Trigger loading state
  dispatch(startLoading(endpoint));
  try {
    const response = await axios(axiosConfig);
    // Return data to dispatch success action in component
    return response.data;
  } catch (error) {
    // Pass error to component for error handling
    throw error;
  } finally {
    // Ensure loading state is cleared even if request fails
    dispatch(stopLoading(endpoint));
  }
};
4. Use in Components

In your React components, use useDispatch and useSelector to trigger the wrapped API calls and display loading bars:

// components/UserProfile.js
import { useDispatch, useSelector } from 'react-redux';
import { apiCallWithLoading } from '../api/helpers';

const UserProfile = () => {
  const dispatch = useDispatch();
  const { loading, user, error } = useSelector(state => state);

  const fetchUser = async () => {
    try {
      const userData = await apiCallWithLoading(
        dispatch,
        'fetchUser',
        { method: 'GET', url: '/api/users/me' }
      );
      dispatch({ type: 'FETCH_USER_SUCCESS', payload: userData });
    } catch (err) {
      dispatch({ type: 'FETCH_USER_ERROR', payload: err.message });
    }
  };

  return (
    <div className="profile-container">
      {/* Show loading bar for this specific endpoint */}
      {loading.fetchUser && <div className="loading-bar">Loading user data...</div>}
      
      <button onClick={fetchUser} disabled={loading.fetchUser}>
        Load My Profile
      </button>
      
      {user && <p>Welcome, {user.name}!</p>}
      {error && <p className="error">{error}</p>}
    </div>
  );
};
Bonus: Global Loading Bar (Simpler Option)

If you don’t need per-endpoint tracking and just want a single global loading bar, simplify the state to a count instead of a flat object:

// initialState.js
const initialState = {
  loadingCount: 0,
  // ...other state
};

// actions.js
export const incrementLoading = () => ({ type: 'INCREMENT_LOADING' });
export const decrementLoading = () => ({ type: 'DECREMENT_LOADING' });

// reducer.js
case 'INCREMENT_LOADING':
  return { ...state, loadingCount: state.loadingCount + 1 };
case 'DECREMENT_LOADING':
  return { ...state, loadingCount: Math.max(0, state.loadingCount - 1) };

Then update the helper function to increment/decrement the count, and show the loading bar in your root App component whenever loadingCount > 0.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:12:36