React新手求助:如何在Redux Action中处理状态并传递错误信息
Fixing Redux Action & Error Handling Issues in Your React App
Hey there! Let's walk through the issues in your code and fix them properly—since you're using Redux (with redux-promise-middleware), state and error handling work differently than plain React, so we'll align your code with Redux best practices.
Key Issues in Your Current Code
- You can't call
this.setStateinside a Redux Action: Actions are meant to describe what happened, not directly modify component state. Plus,thisin your action isn't referencing your Layout component at all—soself.setStatewill throw an error. - Passing
this.state.errorsto the action is unnecessary: Errors should be captured by Redux (via the reducer) and then passed back to your component through props, not the other way around. - Redux-promise-middleware handles promise resolution/rejection for you: You don't need manual
.then()/.catch()in your action, because the middleware automatically dispatches_PENDING,_FULFILLED, and_REJECTEDactions based on the promise's outcome.
1. Updated src/actions/userActions.js
We'll remove manual promise handlers and let the middleware do its job:
import axios from 'axios'; // Replace with your actual API endpoint const API_URL = 'https://your-api-url.com/users'; export function postUsers(username, password) { const userData = { username, password }; return { type: "USERS_POST", payload: axios({ method: 'POST', url: API_URL, data: userData, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', } }) }; }
2. Updated src/components/layout.js
We'll remove the local errors state, fetch errors from the Redux store via props, fix the input name typo, and clean up the action call:
import React, { Component } from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { postUsers } from '../actions/usersAction'; class Layout extends Component { constructor(props) { super(props); this.state = { username: '', password: '', // Removed local errors state—we'll use Redux store's error instead }; } onUserUpdate(field, event) { this.setState({ [field]: event.target.value }); } handlePostUsers(e) { e.preventDefault(); // No need to pass errors—action handles fetching, reducer handles error storage this.props.postUsers(this.state.username, this.state.password); } render() { // Get error state from Redux props const { error, fetching } = this.props.act; return ( <div className="App"> <input name="username" onChange={this.onUserUpdate.bind(this, 'username')} value={this.state.username} placeholder="Username" disabled={fetching} /> {/* Fixed input name from "username" to "password" */} <input name="password" type="password" onChange={this.onUserUpdate.bind(this, 'password')} value={this.state.password} placeholder="Password" disabled={fetching} /> <button onClick={(e) => this.handlePostUsers(e)} disabled={fetching} > {fetching ? 'Submitting...' : 'Go ahead'} </button> {/* Display errors if they exist */} {error.length > 0 && ( <div style={{ color: 'red', marginTop: '1rem' }}> {error.map((err, index) => ( <p key={index}>{err}</p> ))} </div> )} </div> ); } } function mapStateToProps(state) { return { act: state.users, }; } function matchDispatchToProps(dispatch) { return bindActionCreators({ postUsers }, dispatch); } export default connect(mapStateToProps, matchDispatchToProps)(Layout);
3. Minor Adjustment to src/reducers/userReducers.js
Your reducer is mostly correct—we'll ensure we're accessing the right data from axios responses:
const initialState = { fetching: false, fetched: false, users: [], error: [] }; export default function(state = initialState, action) { switch(action.type) { case "USERS_POST_PENDING": { return {...state, fetching: true}; } case "USERS_POST_FULFILLED": { return { ...state, fetching: false, fetched: true, users: [...state.users, action.payload.data] // Axios wraps responses in .data }; } case "USERS_POST_REJECTED": { return { ...state, fetching: false, error: action.payload.response.data // Capture error details from the API }; } default: return state; } }
4. Fix src/index.js
You had an undefined loadingBarMiddleware() call—remove it or import it if you intend to use it:
import React from 'react'; import ReactDOM from 'react-dom'; import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk'; import logger from 'redux-logger'; import promise from 'redux-promise-middleware'; import reducers from './reducers/index'; import { Provider } from 'react-redux'; import registerServiceWorker from './registerServiceWorker'; import Layout from './components/layout'; // Removed undefined loadingBarMiddleware const store = createStore(reducers, applyMiddleware(promise(), thunk, logger)); const app = document.getElementById('root'); ReactDOM.render( <Provider store={store}> <Layout /> </Provider>, app ); registerServiceWorker();
How This Works Now
- When you click the "Go ahead" button,
postUsersis dispatched with your username/password. - Redux-promise-middleware immediately dispatches
USERS_POST_PENDING, which setsfetching: truein your store (we use this to disable inputs/button during loading). - If the API call succeeds: middleware dispatches
USERS_POST_FULFILLED, which adds the new user to your store and marksfetching: false. - If the API call fails: middleware dispatches
USERS_POST_REJECTED, which stores the error data in your store. - Your Layout component receives the error from the store via props, and displays it automatically when it exists.
内容的提问来源于stack exchange,提问作者Liam
相关产品推荐
相关产品推荐

