React 18 Alpha项目Redux store出现非预期状态重复问题及解决
Redux状态重复生成问题排查与修复
项目依赖版本
React 18Alpha - Redux 7.2.4 - redux-thunk 2.3.0 - redux-storage 4.1.2
问题表现
Redux Store状态管理中,reducer会为每个节点重复生成状态,属于非预期表现:
初始代码配置
根reducer定义
const rootReducer = combineReducers({ serverSettings, userSettings, });
初始userSettings reducer逻辑
export default function userSettingsReducer( state: IDefaultState = defaultState, action: UserSettingsAction ): IDefaultState { switch (action.type) { case USER_SETTINGS_SAVE: return { ...state, userSettings: action.userSettings }; case USER_SETTINGS_LOAD: return { ...state, userSettings: action.userSettings }; default: return state; } }
action定义
export const ActionSaveUserSettings = (userSettings: UserSettings) => (dispatch: Dispatch<UserSettingsAction>) => { dispatch({ type: USER_SETTINGS_SAVE, userSettings: userSettings }); };
action触发示例
const handleOrderSizesChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => { dispatch(ActionSaveUserSettings({ ...userSettings, OrderSizes: { ...userSettings.OrderSizes, [e.target.name]: e.target.value } })) }
store配置代码
import { createStore, combineReducers, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import { composeWithDevTools } from 'redux-devtools-extension'; import { createLogger } from 'redux-logger'; import serverSettings from "./reducers/serverSettingsReducer"; import userSettings from './reducers/userSettingsReducer'; import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'; import { save, load } from "redux-localstorage-simple" const rootReducer = combineReducers({ serverSettings, userSettings, }); const logger = createLogger(); const enhancer = composeWithDevTools(applyMiddleware(save(), thunk, logger)); export const store = createStore(rootReducer, load(), enhancer); export type RootState = ReturnType<typeof store.getState> export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector export type AppDispatch = typeof store.dispatch export const useAppDispatch = () => useDispatch<AppDispatch>() export default store;
默认状态类型定义
export interface IDefaultState { serverSettings: ServerSettings; userSettings: UserSettings; }
修复方案
调整userSettings reducer的参数和返回逻辑即可解决问题:
export default function userSettingsReducer( state: UserSettings = defaultState.userSettings, action: UserSettingsAction ): UserSettings { switch (action.type) { case USER_SETTINGS_SAVE: return { ...state, ...action.userSettings }; case USER_SETTINGS_LOAD: return { ...state }; default: return state; } }
问题根因
combineReducers的作用是将多个子reducer合并,每个子reducer仅负责管理根状态中对应命名的切片:比如给combineReducers传入userSettings: userSettingsReducer,那么userSettingsReducer的入参state就只是根状态中userSettings字段的值,返回值也直接作为根状态userSettings字段的新值。
之前的错误写法有两个:
- 给
userSettingsReducer的初始状态设置为完整的根状态IDefaultState,而非UserSettings类型的切片 - reducer返回值中额外嵌套了一层
userSettings字段,导致最终状态出现store.userSettings.userSettings的重复嵌套结构
修复后子reducer仅处理自己负责的状态切片,就解决了重复生成状态的问题。
内容的提问来源于stack exchange,提问作者Shane Bird
相关产品推荐
相关产品推荐

