React Redux错误Reducer的实现逻辑与写法咨询
我明白你现在对Redux里错误reducer的写法还有困惑,咱们一步步把这个问题理清楚~
Redux错误处理的两种常见思路
Redux里的错误管理没有绝对的标准写法,但通常有两种主流模式,你可以根据自己的应用规模和需求选择:
1. 分散式:业务reducer自身处理相关错误
这种模式下,错误状态和对应的业务状态放在同一个reducer里,逻辑更内聚,适合小型应用或者错误场景比较单一的模块。比如你的activeUser reducer,完全可以自己管理登录相关的错误:
// activeUser/reducer.js import * as actionTypes from '../../constants' const initialState = { user: null, loginErrors: { wrongUsername: false, wrongPassword: false, networkError: false } } export const activeUserReducer = (state = initialState, action) => { switch(action.type) { case actionTypes.LOGIN_SUCCESS: return { ...state, user: action.payload, loginErrors: { ...initialState.loginErrors } // 登录成功后清空所有错误 } case actionTypes.LOGIN_FAILED_WRONG_USERNAME: return { ...state, loginErrors: { ...state.loginErrors, wrongUsername: true } } case actionTypes.LOGIN_FAILED_WRONG_PASSWORD: return { ...state, loginErrors: { ...state.loginErrors, wrongPassword: true } } case actionTypes.LOGIN_FAILED_NETWORK: return { ...state, loginErrors: { ...state.loginErrors, networkError: true } } // 用户重新输入时清空错误 case actionTypes.CLEAR_LOGIN_ERRORS: return { ...state, loginErrors: { ...initialState.loginErrors } } default: return state } }
2. 集中式:单独的Error Reducer统一管理所有错误
如果你的应用有很多模块(登录、注册、商品加载等),想把所有错误状态集中管理,就可以用这种方式。你现在尝试拆分单独的错误reducer的思路是对的,但不需要给每个错误单独写reducer(会导致文件太散),可以用一个统一的reducer来管理不同模块的错误:
// error/index.js import * as actionTypes from '../../constants' const initialState = { login: { wrongUsername: false, wrongPassword: false, networkError: false }, // 可以扩展其他模块的错误 register: { emailExists: false, passwordTooShort: false } } export const errorReducer = (state = initialState, action) => { switch(action.type) { // 登录错误处理 case actionTypes.LOGIN_FAILED_WRONG_USERNAME: return { ...state, login: { ...state.login, wrongUsername: true } } case actionTypes.LOGIN_FAILED_WRONG_PASSWORD: return { ...state, login: { ...state.login, wrongPassword: true } } case actionTypes.LOGIN_SUCCESS: case actionTypes.CLEAR_LOGIN_ERRORS: return { ...state, login: { ...initialState.login } // 清空登录相关错误 } // 注册错误处理示例 case actionTypes.REGISTER_FAILED_EMAIL_EXISTS: return { ...state, register: { ...state.register, emailExists: true } } default: return state } }
然后记得在store里把这个reducer合并进去:
// store.js import { combineReducers, createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' // 如果用异步action的话 import { activeUserReducer } from './activeUser' import { errorReducer } from './error' const rootReducer = combineReducers({ activeUser: activeUserReducer, errors: errorReducer }) export const store = createStore(rootReducer, applyMiddleware(thunk))
组件中如何使用错误状态
不管用哪种模式,组件里都可以通过useSelector(React-Redux)获取错误状态,然后展示对应的提示:
import { useSelector, useDispatch } from 'react-redux' import { clearLoginErrors } from '../../actions/loginActions' const LoginForm = () => { const dispatch = useDispatch() const { wrongUsername, wrongPassword } = useSelector(state => state.errors.login) // 用户输入时自动清空错误提示 const handleInputChange = () => { if (wrongUsername || wrongPassword) { dispatch(clearLoginErrors()) } } return ( <div className="login-form"> {wrongUsername && <p className="error-text">用户名不存在,请检查后重试</p>} {wrongPassword && <p className="error-text">密码错误,请重新输入</p>} <input type="text" placeholder="用户名" onChange={handleInputChange} /> <input type="password" placeholder="密码" onChange={handleInputChange} /> <button>登录</button> </div> ) }
补充:异步Action中的错误触发
如果你的登录逻辑是异步的(比如调用后端API),通常在异步action creator里根据API返回结果触发对应的错误动作:
// actions/loginActions.js import * as actionTypes from '../../constants' export const login = (username, password) => async (dispatch) => { try { const response = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }) const data = await response.json() if (response.ok) { dispatch({ type: actionTypes.LOGIN_SUCCESS, payload: data.user }) } else { // 根据后端返回的错误类型触发对应动作 if (data.errorCode === 'WRONG_USERNAME') { dispatch({ type: actionTypes.LOGIN_FAILED_WRONG_USERNAME }) } else if (data.errorCode === 'WRONG_PASSWORD') { dispatch({ type: actionTypes.LOGIN_FAILED_WRONG_PASSWORD }) } } } catch (err) { // 捕获网络错误 dispatch({ type: actionTypes.LOGIN_FAILED_NETWORK }) } }
内容的提问来源于stack exchange,提问作者Dennis Braun
相关产品推荐
相关产品推荐

