我有一个看起来像这样的reducer树:
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: combineReducers({
sets,
boosters
}),
servers: combineReducers({
servers
})
})
});
现在setup
密钥包含一个表单,一旦我们提交它就需要重置。但是我无法访问整个setup
树,因为使用combineReducers意味着reducers仅操作树的叶节点处的数据(在这种情况下为sets
和boosters
)。 / p>
我的第一个冲动是创建一个减少整个设置树的函数,如下所示:
function setup(state, action){
//If there's an action that affects this whole tree, handle it
switch(action.type){
case "FORM_SUBMIT": //DO STUFF
break;
}
//Otherwise just let the reducers care about their own data
return combineReducers({
sets,
boosters
})(state);
}
但这不起作用,并且还弄乱了我的第一个代码示例的漂亮树结构。
使用redux有更好的解决方案吗?
答案 0 :(得分:8)
combineReducers
是一个很好的模式,因为它倾向于强制执行减速器应该限定为商店的非重叠子集的想法,与商店本身的结构分离。它认为你应该减少树叶而不是树枝,它会处理树枝的减少。
尽管如此,使用替代模式可能有充分的理由。正如我在稍微related question中提到的那样,您可以选择退出纯粹使用combineReducers
并根据需要分解您的缩减器。
在您的情况下,您可以装饰内在的combineReducers
:
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: setupReducer(
combineReducers({
sets,
boosters
})
),
servers: combineReducers({
servers
})
})
});
此处setupReducer
是higher-order function。这可能很难理解,但这就是我如何处理它:
setupReducer
会将reducer作为参数,因为我们会将combineReducers
的结果传递给它。combineReducers
返回的reducer签名是(state, action) => state
。 setupReducer
必须返回一个reducer,它同样是签名(state, action) => state
的函数。换句话说,它需要一个reducer,并返回一个reducer:((state, action) => state) => ((state, action) => state)
。所以它可能看起来像:
function setupReducer(subReducer) {
return (state, action) => {
//If there's an action that affects this whole tree, handle it
switch(action.type){
case "FORM_SUBMIT":
// ... create newState
return newState;
default:
return subReducer(state, action);
}
}
}
我保持你的逻辑流程在上面,但为了提醒你,你可能想要无条件地调用subReducer
然后修改它的输出。否则,您必须确保未被调用的分支始终生成相同形状的对象,这似乎是耦合的潜在粘性点。
答案 1 :(得分:0)
@ acjay的回答是个好主意!我只是想使用旧方法reducer(state, action)
而不是更高阶函数。所以我创建了一个以主从关系组合reducer的方法。
<强> MasterSlave 强>
export default function masterSlaveReducer(reducerMaster, reducerSlave) {
return (state, action) => {
const newState = reducerMaster(state, action);
if(newState === state){
return reducerSlave(state, action);
}
return newState;
};
}
Miguel的代码将以这种方式使用:
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: masterSlaveReducer(
setup, // setup() from Miguel's question
combineReducers({
sets,
boosters
})
),
servers: combineReducers({
servers
})
})
});