React Redux Boilerplate流程学习咨询:已梳理API调用流程求验证
Hey there! Let's break down and validate your current flow, then fill in all the missing pieces to give you a full end-to-end picture of how a typical React Redux async flow works in a boilerplate setup.
First: Your Initial Step is Correct!
You're right to trigger the action from componentDidMount—this is the standard lifecycle method to kick off data-fetching once your component is mounted to the DOM. Let's expand this into the full flow:
Full End-to-End Flow Steps
1. View Layer (Component): Trigger Action on Mount
Your component uses componentDidMount to call the mapped action creator from props. Don't forget that this action creator gets injected via Redux's connect HOC:
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { getCampaignTopics } from '../modules/campaigns'; // Import your action creator class CampaignList extends Component { componentDidMount() { // Trigger the action with your parameter (e.g., page 1) this.props.getCampaignTopics(1); } render() { // Later, we'll use the fetched data from state here const { campaignTopics, isLoading, error } = this.props; if (isLoading) return <div>Loading...</div>; if (error) return <div>Error: {error.message}</div>; return ( <ul> {campaignTopics.map(topic => ( <li key={topic.id}>{topic.title}</li> ))} </ul> ); } } // Map Redux state to component props const mapStateToProps = (state) => ({ campaignTopics: state.campaigns.topics, isLoading: state.campaigns.isLoading, error: state.campaigns.error }); // Map action creators to component props const mapDispatchToProps = { getCampaignTopics }; // Connect component to Redux store export default connect(mapStateToProps, mapDispatchToProps)(CampaignList);
2. Modules Layer (Action Creator & Async Logic)
Your getCampaignTopics action creator is likely a Redux Thunk (since it's handling async API calls—boilerplates almost always use thunks for async). Here's what the complete implementation should look like:
// ../modules/campaigns.js import axios from 'axios'; // Or your preferred HTTP client // Action Types export const CAMPAIGN_TOPICS_REQUEST = 'CAMPAIGN_TOPICS_REQUEST'; export const CAMPAIGN_TOPICS_SUCCESS = 'CAMPAIGN_TOPICS_SUCCESS'; export const CAMPAIGN_TOPICS_FAILURE = 'CAMPAIGN_TOPICS_FAILURE'; // Action Creators const requestCampaignTopics = () => ({ type: CAMPAIGN_TOPICS_REQUEST }); const receiveCampaignTopics = (topics) => ({ type: CAMPAIGN_TOPICS_SUCCESS, payload: topics }); const failCampaignTopics = (error) => ({ type: CAMPAIGN_TOPICS_FAILURE, payload: error }); // Async Action Creator (Thunk) export const getCampaignTopics = (page) => { return async (dispatch) => { dispatch(requestCampaignTopics()); // Trigger loading state try { const response = await axios.get(`/api/campaigns/topics?page=${page}`); dispatch(receiveCampaignTopics(response.data)); // Send fetched data to reducer } catch (error) { dispatch(failCampaignTopics(error)); // Handle errors } }; };
3. Reducer Layer: Update State Based on Actions
The reducer listens for the action types we defined and updates the corresponding slice of Redux state:
// ../modules/campaigns.js (continued) const initialState = { topics: [], isLoading: false, error: null }; export const campaignsReducer = (state = initialState, action) => { switch (action.type) { case CAMPAIGN_TOPICS_REQUEST: return { ...state, isLoading: true, error: null }; case CAMPAIGN_TOPICS_SUCCESS: return { ...state, isLoading: false, topics: action.payload }; case CAMPAIGN_TOPICS_FAILURE: return { ...state, isLoading: false, error: action.payload }; default: return state; } };
4. Store Setup (Boilerplate Core)
Don't forget that your boilerplate should have a root reducer and store configured to use thunks:
// ../store/index.js import { createStore, combineReducers, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import { campaignsReducer } from '../modules/campaigns'; const rootReducer = combineReducers({ campaigns: campaignsReducer }); export const store = createStore( rootReducer, applyMiddleware(thunk) // Enable thunks for async actions );
5. Wrap App with Provider
Finally, your root App component is wrapped with Redux's Provider to make the store available to all connected components:
// ../index.js import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import { store } from './store'; import CampaignList from './components/CampaignList'; ReactDOM.render( <Provider store={store}> <CampaignList /> </Provider>, document.getElementById('root') );
Quick Recap of Your Original Flow
Your initial step (calling the module's action creator from componentDidMount) is exactly the right starting point. The missing pieces were the async thunk logic, reducer state updates, connecting the component to state, and the core store setup that ties everything together.
内容的提问来源于stack exchange,提问作者Bik

