Javascript 用于更新Redux状态的多个部分的模式
我的Redux状态的形状如下所示:Javascript 用于更新Redux状态的多个部分的模式,javascript,redux,Javascript,Redux,我的Redux状态的形状如下所示: { user: { id: 123, items: [1, 2] }, items: { 1: { ... }, 2: { ... } } } 使用组合减速器,我有两套减速器。每个操作都作用于状态的一个根键。i、 e.一个管理用户键,另一个管理项键 如果我想添加一个可以调用2个reducer的项,第一个将向项添加一个新对象,第二个将向user.items数组添加id 这有
{
user: {
id: 123,
items: [1, 2]
},
items: {
1: {
...
},
2: {
...
}
}
}
使用组合减速器,我有两套减速器。每个操作都作用于状态的一个根键。i、 e.一个管理用户
键,另一个管理项
键
如果我想添加一个可以调用2个reducer的项,第一个将向项
添加一个新对象,第二个将向user.items
数组添加id
这有一种不好的代码味道。我觉得应该有一种方法可以在原子上同时减少两个对象的状态。i、 e.除子减速器外,还有一个作用于根对象的根减速器。这可能吗?我认为你所做的实际上是正确的 在调度操作时,从根减速器开始,将调用每个“子减速器”,将相应的“子状态”和操作传递给下一层子减速器。您可能认为这不是一个好的模式,因为每个“子减速器”都会被调用并一直传播到状态树的每个叶节点,但事实并非如此 如果在开关案例中定义了该动作,“子减速器”将只更改其拥有的“子状态”部分,并可能将该动作传递到下一层,但如果“子减速器”中未定义该动作,则它将不执行任何操作并返回当前“子状态”,从而停止传播 让我们看一个更复杂的状态树示例
假设您使用
redux simple router
,我将您的情况扩展为更复杂(具有多个用户的数据),那么您的状态树可能如下所示:
{
user: {
id: 123,
items: [1, 2]
},
items: {
1: {
...
},
2: {
...
}
}
}
{
当前用户:{
洛格丁:没错,
id:123,
},
实体:{
用户:{
123: {
id:123,
项目:[1、2]
},
456: {
身份证号码:456,
项目:[……]
}
},
项目:{
1: {
...
},
2: {
...
}
}
},
路由:{
变更号:3,
路径:“/”,
状态:未定义,
替换:false
}
}
正如您已经看到的,在状态树中有嵌套的层,为了解决这个问题,我们使用了reducer composition
,其概念是为状态树中的每个层使用combineReducer()
。
因此,减速器应如下所示:
(为了说明逐层的概念,这是由外向内的,因此顺序是向后的)
第一层:
从“redux简单路由器”导入{routeReducer}
函数currentUserReducer(状态={},操作){
开关(action.type){…}
}
const rootReducer=combinereducer({
currentUser:currentUserReducer,
实体:entitiesReducer,//来自第二层
路由:routeReducer//来自“redux简单路由器”
})
第二层(实体部分):
函数usersReducer(状态={},操作){
开关(动作类型){
案例添加项目:
案例类型二:
案例类型_树:
返回Object.assign({},state{
//您可以将其视为将其传递到“第三层”
[action.userId]:itemsusinerreducer(状态[action.userId],action)
})
案例类型四:
返回。。。
违约:
返回状态
}
}
函数项还原程序(…){…}
const entitiesReducer=组合减速机({
用户:usersReducer,
项目:项目还原器
})
第三层(实体、用户、项目):
/**
*注意:这里只调用ADD_ITEM,TYPE_TWO,TYPE_TREE,
*没有其他类型将传播到此减速器
*/
函数itemsusinerreducer(状态={},操作){
开关(动作类型){
案例添加项目:
返回Object.assign({},state{
items:state.items.concat([action.itemId])
//或项:[…state.items,action.itemId]
})
案例类型二:
回来做点什么
案例类型_树:
回来做点别的
违约:
声明:
}
}
当一个动作发出时
redux将从rootReducer调用每个子reducer,通过:
currentUser:{…}
子状态和整个动作到currentUserReducer
实体:{users:{…},items:{…}
和对entitiesReducer的操作
路由:{…}
和对路由转换器的操作
和…
entitiesReducer
将用户:{…}
和操作传递给用户reducer
,和
items:{…}
和对itemsReducer的操作
为什么这样好?
您提到过有一种方法可以让根减速器处理状态的不同部分,而不是将它们传递给单独的子减速器。但是,如果您不使用reducer合成并编写一个巨大的reducer来处理状态的每一部分,或者您只是将状态嵌套到一个深度嵌套的树中,那么随着应用程序变得更加复杂(比如每个用户都有一个[friends]
数组,或者项目可以有[tags]
,等等),如果不是不可能找出每一个案例,那将是极其复杂的
此外,拆分reducer使您的应用程序非常灵活,您只需将任何案例类型\u NAME
添加到reducer即可对该操作作出反应(只要您的父reducer将其传递下去)
例如,如果要跟踪用户是否访问某条路线,只需将案例更新路径添加到减速器开关中即可 当您解释操作会向下传播所有子约简时,我终于明白了,不管它们是否具有该操作。事后看来,这似乎很明显,但我终于看到了如何在Redux存储中处理关系数据的清晰模式。谢谢