如何用Redux combineReducers实现含自有属性的嵌套reducer结构
如何在Redux中让addPage节点同时包含子reducer和自身属性
要实现你想要的状态结构,核心思路是不能直接用combineReducers生成addPage节点——因为combineReducers只能让每个子reducer对应独立的状态节点,无法处理父节点自身的属性。你需要手动编写一个顶层的addPageReducer,它既要处理自身的shopListDisplayed和rerenderKey属性,又要调用combineReducers来管理product和shop这两个子节点。
下面是具体的实现步骤和代码示例:
1. 先定义子reducer(product和shop)
先写好负责product和shop状态的独立reducer,和平时的写法一样:
// productReducer.js const initialProductState = { /* 你的product初始状态 */ }; export const productReducer = (state = initialProductState, action) => { switch(action.type) { case 'ADD_PRODUCT': return {...state, ...action.payload}; // 其他product相关action处理 default: return state; } }; // shopReducer.js const initialShopState = { /* 你的shop初始状态 */ }; export const shopReducer = (state = initialShopState, action) => { switch(action.type) { case 'UPDATE_SHOP_INFO': return {...state, ...action.payload}; // 其他shop相关action处理 default: return state; } };
2. 定义addPage的初始状态
这个状态要同时包含自身属性和子reducer的初始值:
const initialAddPageState = { shopListDisplayed: false, rerenderKey: 0, product: initialProductState, // 对应productReducer的初始状态 shop: initialShopState // 对应shopReducer的初始状态 };
3. 编写addPage的顶层reducer
这个reducer是核心:它先处理自身属性的action,再把非自身的action转发给子reducer处理:
import { combineReducers } from 'redux'; import { productReducer, shopReducer } from './path-to-reducers'; // 先用combineReducers把product和shop的reducer合并成一个子处理函数 const addPageChildReducers = combineReducers({ product: productReducer, shop: shopReducer }); // 编写addPage的顶层reducer export const addPageReducer = (state = initialAddPageState, action) => { // 优先处理addPage自身属性的action switch(action.type) { case 'TOGGLE_SHOP_LIST_DISPLAY': return { ...state, shopListDisplayed: !state.shopListDisplayed }; case 'INCREMENT_RENDER_KEY': return { ...state, rerenderKey: state.rerenderKey + 1 }; // 其他自身属性的action都在这里处理 default: // 非自身的action,交给子reducer处理product和shop的状态更新 const updatedChildState = addPageChildReducers(state, action); return { ...state, ...updatedChildState }; } };
4. 将addPageReducer加入根reducer
最后把addPageReducer放到根combineReducers中,作为addPage节点的处理函数:
import { combineReducers } from 'redux'; import { addPageReducer } from './path-to-addPageReducer'; const rootReducer = combineReducers({ addPage: addPageReducer, // 其他根节点的reducer... }); export default rootReducer;
最终的状态结构
这样配置后,你的Redux状态就会变成你想要的样子:
{ addPage: { shopListDisplayed: false, rerenderKey: 0, product: { /* productReducer管理的状态 */ }, shop: { /* shopReducer管理的状态 */ } } }
补充说明
如果你的子reducer数量很少,也可以不用combineReducers,手动转发action给子reducer,比如:
export const addPageReducer = (state = initialAddPageState, action) => { switch(action.type) { // 处理自身属性的action... default: return { ...state, product: productReducer(state.product, action), shop: shopReducer(state.shop, action) }; } };
这种写法更直观,但子reducer多的时候会比较繁琐,推荐用combineReducers来简化代码。
内容的提问来源于stack exchange,提问作者BeniaminoBaggins




