我们假设我有一个这样的结构,这是从API获取并使用" normalizr"在我的实体上:
entities: {
users:{
1: {
name: 'John',
posts: [ 1, 4 ]
}
},
posts: {
1: {
name: 'First Post',
},
4: {
name: 'Second Post',
}
}
}
现在我有一个按用户过滤帖子的方法,基本上可以这样做:
let filteredPosts = {};
entities.users.posts.forEach(key => {
if(posts.hasOwnProperty(key))
filteredPosts[key] = posts[key]
});
显示该用户帖子的页面,例如:
render() {
return(
<div>
{Object.keys(filteredPosts).map(key => {
return (
<div>{filteredPosts[key].name}</div>
);
})}
</div>
)
}
我的实体reducer非常简单:
import { merge } from 'lodash';
...
function entities(state = { users: {}, posts: {} }, action) {
if (action.response && action.response.entities) {
return merge({}, state, action.response.entities);
}
return state;
}
现在,如果我向API请求为该用户添加帖子,返回新创建的帖子记录,该记录将自动添加到我的实体上的帖子中。
我如何处理更新用户以反映该更改,以便用户现在有3个帖子,数组中有新的帖子ID?
我应该创建一个reducer并听取帖子创建操作,并更新那里的state.entities.users.posts
吗?重新构建实体似乎不是一种选择。最好的方法是什么?
由于
更新:
这是我现在必须使用的解决方案,以保持数据的一致性。我修改了对帐户创建的帖子ID的回复。我知道这可以分解为多个reducer,但我仍然想知道是否有更好更直接的方法,我不必为每个嵌套实体执行此操作。
function entities(state = {}, action) {
...
if(action.type === 'POST_ADD_SUCCESS') {
// Get the user id from the created post
let userId = response.entities.posts[response.result].userId;
// Add the user with all his posts to the response
response.entities.users = {
[userId]: {
posts: [...state.users[userId].posts, response.result]
}
}
}
...
// Merge normally
return merge({}, state, response.entities);
}
答案 0 :(得分:1)
您更新后的代码段主要沿着正确的路径展开,但我不确定您为什么仍然引用&#34;响应&#34;在那里。您的动作创建者函数可能应该抓取用户ID和帖子ID,并且当AJAX调用成功时,创建一个看起来像{type : POST_ADD_SUCCESS, userId : userId : postId}
的动作。换句话说,减速器不应该知道任何关于“响应”的信息。根本就是它应该添加帖子ID&#39; x&#39;到用户ID列表&#39; y&#39;。
答案 1 :(得分:0)
为什么不使用normalizr作为中间件而不是自己滚动?像https://github.com/wbinnssmith/redux-normalizr-middleware
这样的东西答案 2 :(得分:0)
您是否考虑在API成功发布时使用格式化实体调度新操作?
const foo = (entities) => {
type: "POST_ADD_SUCCESS"
response : { entities }
}
操作类型无关紧要,因为您的实体reducer无论如何都会拦截操作