我目前正在使用Redux,我不清楚将reducer绑定到sub,动态设置状态的正确方法是什么。
例如,假设我的状态看起来像这样(在从后端API异步获取一些数据之后)
{
"categories": {
"collection": {
"42": {
"id": "42",
"title": "whatever",
"owner_id": "10"
"posts": {
"collection": {
"36": {
"id": "36",
"title": "hello",
"content": "hello world"
},
"37": { // more posts ... }
},
"ids": ["36", "37", ...]
},
"otherChildren": { // more sub-entities }
},
"43": { // more categories ... }
},
"ids": ["42", "43", ...]
},
"users": {
"collection": {
"10": {
"id": "10"
"email": "what@ever.com"
},
"11": { // more users ... }
},
"ids": [10, 11]
}
}
我的根减速器看起来像这样:
export default combineReducers({
categories: categoriesReducer,
users: usersReducer
})
和categoriesReducer:
function categoriesReducer(state = initialState, action) {
switch (action.type) {
case FETCH_ALL_CATEGORIES_SUCCESS:
return Object.assign({}, state, {
categories: {
collection: action.payload
}
})
default:
return state
}
}
现在我要做的是使用postsReducer函数无缝地委托处理状态的post
子集部分,基本上添加一个例如:
case FETCH_CATEGORY_ALL_POSTS_SUCCESS:
let categoryId = action.categoryId
return Object.assign({}, state, {
categories: {
[categoryId]: combineReducers({
"posts": postsReducer,
"otherChildren": otherChildrenReducer
})
}
}
当然,这不起作用。我没有得到的是如何让redux使用combineReducer为嵌套的reducer自动更新状态的子集,同时自动将正确的子集作为state参数传递给reducer函数,而不会覆盖现有数据(即我的例子。)
我设法让这项工作编写了我自己的“委托”功能,但感觉非常错误 - 特别是看https://github.com/reactjs/redux/blob/master/src/combineReducers.js看起来就像这样做。
传统上,我怎么想这样做?甚至可以使用combineReducers与Redux一样,我是否误解了combineReducer的观点,还是我期待它的魔力呢?
谢谢!
修改/更新:
我确实需要嵌套的那些(对,也许category
/ post
示例不正确)并且我想要减速器(即这里,postsReducer,但它可以是Collection
缩减器,可以在多个地方重复使用。
(为什么我希望它嵌套?实际上在这个例子中,假设一个post
只能属于一个category
,因为{{{ 1}}实际上是使用来自post
的私钥加密的。这就是为什么代表这个链,这个关系在状态中对我来说非常敏感)
在传递状态的正确子集时,还没有办法让redux委托给其他reducer - 例如,将状态category
传递给postReducer吗?
答案 0 :(得分:0)
你在商店这么好的地方,为什么不继续分离所有不同的收藏品。
我的意思是你的帖子应该/可能有另一个减速器,商店会像这样:
{
categories: [],
posts: [],
users: []
}
您的类别将仅包含帖子的ID
所以你可以在两个reducer(类别和新帖子reducer)中“捕获”“FETCH_ALL_CATEGORIES_SUCCESS”动作,在categoryReducer上你可以保护类别数据和ID,而postsReducer只会保存帖子
答案 1 :(得分:0)
您在上一个代码段中以错误的方式使用combineReducers。 (在您使用它将categoriesReducer和usersReducer组合在一起的第一个片段中是正确的。)
对于FETCH_CATEGORY_ALL_POSTS_SUCCESS,不要调用combineReducers,只需调用categoriesReducer中的普通函数。
posts: posts(action.payload.posts)
普通功能基本上是一个减速器。这是你自己写的,你可能把它放在同一个文件中。
但上面代码的另外两个主要问题是:
1)正如另一位用户已经说过的那样,将帖子存储为类别的子属性可能不是最好的。而是将帖子存储为状态树中的自己的项目,并且每个帖子只有一个category_id
字段以显示它属于哪个类别。因此,在这种情况下,您的状态树将如下所示:
{
categories: {},
posts: {},
users: {}
}
你最初会将combineReducers用作:
export default combineReducers({
categories: categoriesReducer,
posts: postsReducer,
users: usersReducer
})
2)在categoriesReducer(或任何相关内容)中,您不必拥有categories
属性,因为您在调用combineReducers
时已经创建了该属性。换句话说,在categoriesReducer
你应该只是这样:
function categoriesReducer(state = initialState, action) {
switch (action.type) {
case FETCH_ALL_CATEGORIES_SUCCESS:
return Object.assign({}, state, {
collection: action.payload,
ids: // function to extract ids goes here
});
default:
return state;
}
}