我想要的是根减速器结合其他减速器,并听取额外的动作。我找到了文档,但我无法获得任何信息。
这是一些伪代码。
const root1 = combineReducers({
reducer1,
reducer2,
reducer3,
reducer4
});
function root2(state = initState, action) {
switch (action.type) {
case LOAD_DATA:
return _.assign({}, initState, action.data);
default:
return state;
}
}
merge(root1, root2);
我弄清楚的唯一方法是删除combineReducers:
function root(state = initState, action) {
switch (action.type) {
case LOAD_DATA:
return _.assign({}, initState, action.data);
case ...: return ...;
case ...: return ...;
case ...: return ...;
default: return state;
}
}
还有其他方法可以实现吗?
答案 0 :(得分:3)
是,您可以将combineReducers()
与多个Reducer配合使用,同时还可以执行重建整个应用程序状态的操作。不可否认,这是一个奇怪的设计决策,并且不能很好地扩展到更复杂的应用程序,但你显然有一个用例。如果你想做这样的事情,你有两个选择。
在多个reducer函数中侦听相同的动作类型是完全有效的。这是最简单的方法,虽然它涉及更多的重复。您只需将您的操作返回的每个状态分解为适用的各个reducer函数。
例如,如果这是您的整个申请状态
{
foo: {},
bar: {}
}
重建整个应用程序状态的操作类型为LOAD_DATA
,您可以执行此操作
function foo (state = {}, action) {
switch (action.type) {
case 'LOAD_DATA':
return {...state, action.result.foo}
}
}
function bar (state = {}, action) {
switch (action.type) {
case 'LOAD_DATA':
return {...state, action.result.bar}
}
}
const root = combineReducers({
foo,
bar
});
这样,状态中的foo
和bar
将始终使用来自相同操作的相应数据进行重建。
没有什么可以阻止您构建自己的combineReducers()
版本。如果您从头开始构建combineReducers()
函数时看{4}},您会发现现有的逻辑并不复杂。您只需要侦听特定的操作类型,并在匹配时从该操作返回整个状态。这是我通过查看this video然后将2个util函数用于该函数而构建的版本
function combineReducers(reducers) {
var fn = (val) => typeof val === 'function';
var finalReducers = Object.keys(reducers).reduce((result, key) => {
if (fn(reducers[key])) {
result[key] = reducers[key]
}
return result
}, {});
return function combination(state = {}, action) {
if (action.type === 'LOAD_DATA') {
return completeStateReducer(action)
} else {
var hasChanged = false
var fn = (reducer, key) => {
var previousStateForKey = state[key]
var nextStateForKey = reducer(previousStateForKey, action)
if (typeof nextStateForKey === 'undefined') {
var errorMessage = getUndefinedStateErrorMessage(key, action)
throw new Error(errorMessage)
}
hasChanged = hasChanged || nextStateForKey !== previousStateForKey
return nextStateForKey
}
var finalState = Object.keys(finalReducers).reduce((result, key) => {
result[key] = fn(finalReducers[key], key)
return result
}, {})
return hasChanged ? finalState : state
}
}
}
function completeStateReducer(action) {
return action.result;
}
在重新合并这些util函数之外,我真正添加的唯一内容是关于监听LOAD_DATA
操作类型然后在发生这种情况时调用completeStateReducer()
而不是组合其他reducer函数。当然,这假设您的LOAD_DATA
动作实际上会返回您的整个状态,但即使它没有,这也应该指向您构建自己的解决方案的正确方向。
答案 1 :(得分:2)
首先,combineReducers
仅仅是一个实用函数,它简化了“此reducer函数应处理对此数据子集的更新”的常见用例。这不是必需的。
其次,这看起来几乎是https://github.com/acdlite/reduce-reducers的确切用例。这里有一个例子:https://github.com/reactjs/redux/issues/749#issuecomment-164327121
export default reduceReducers(
combineReducers({
router: routerReducer,
customers,
stats,
dates,
filters,
ui
}),
// cross-cutting concerns because here `state` is the whole state tree
(state, action) => {
switch (action.type) {
case 'SOME_ACTION':
const customers = state.customers;
const filters = state.filters;
// ... do stuff
}
}
);
另外,我举例说明了在Redux文档的“结构化减速机”部分中使用reduceReducers
:http://redux.js.org/docs/recipes/reducers/BeyondCombineReducers.html。