Redux新手求助:如何从异步Action的Reducer中取回数据
Hey there! Since you're new to Redux, let's walk through how to fix this and get your user data into the reducer properly. The core issue here is that plain Redux doesn't handle async actions out of the box—right now you're dispatching an action with a Promise as the payload, but the reducer will just get the Promise object itself, not the resolved data once the request finishes.
Let's Fix This Step by Step
1. Use Redux Thunk Middleware
Redux Thunk is the simplest middleware for handling async actions, perfect for beginners. It lets you write action creators that return functions (instead of plain objects) so you can handle async logic, then dispatch actions once the Promise resolves.
First, install it if you haven't already:
npm install redux-thunk
Then add it to your Redux store setup:
import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './your-reducer-file'; const store = createStore(rootReducer, applyMiddleware(thunk));
2. Refactor Your mapDispatchToProps
Instead of dispatching an action with a Promise payload directly, we'll handle the async request inside a function, then dispatch success/failure actions once we have data (or an error):
const mapDispatchToProps = (dispatch) => { return { fetchUserList: () => { console.log('---In fetchUserList---'); // Optional: Dispatch a "request started" action for loading states dispatch({ type: FETCH_USER_LIST_REQUEST }); // Create your async request Promise const fetchUsers = new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); console.log('xhr: ', xhr); xhr.open('GET', 'http://localhost:5000/data/fetch/users'); xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 300) { // Resolve with parsed JSON data resolve(JSON.parse(xhr.responseText)); } else { reject(new Error(xhr.statusText)); } }; xhr.onerror = () => reject(new Error('Network request failed')); xhr.send(); // Don't forget to send the request! }); // Handle Promise resolution/rejection fetchUsers .then(userData => { // Dispatch success action with the actual user data dispatch({ type: FETCH_USER_LIST_SUCCESS, payload: userData }); }) .catch(error => { // Dispatch failure action with error message dispatch({ type: FETCH_USER_LIST_FAILURE, payload: error.message }); }); } }; };
3. Update Your Reducer to Handle the New Actions
Now your reducer can listen for the success action and grab the data from action.payload:
// Define initial state with loading/error states (optional but recommended) const initialState = { userList: [], isLoading: false, fetchError: null }; const userReducer = (state = initialState, action) => { switch (action.type) { case FETCH_USER_LIST_REQUEST: return { ...state, isLoading: true, fetchError: null }; case FETCH_USER_LIST_SUCCESS: return { ...state, isLoading: false, userList: action.payload // Here's your resolved user data! }; case FETCH_USER_LIST_FAILURE: return { ...state, isLoading: false, fetchError: action.payload }; default: return state; } }; export default userReducer;
4. Access the Data in Your Component
Use mapStateToProps to pull the user data (and loading/error states) from the store into your component:
const mapStateToProps = (state) => { return { users: state.userReducer.userList, // Match your reducer's key in the root reducer isLoading: state.userReducer.isLoading, fetchError: state.userReducer.fetchError }; }; // Connect both functions to your component export default connect(mapStateToProps, mapDispatchToProps)(YourComponent);
Why Your Original Code Didn't Work
Plain Redux reducers are pure, synchronous functions. When you dispatched the action with a Promise payload, the reducer ran immediately—before the Promise resolved. That means the reducer got the Promise object, not the user data you wanted. Redux Thunk solves this by letting you delay dispatching the final action until the async work is done.
内容的提问来源于stack exchange,提问作者HVenom

