我使用redux和normalizr来规范化服务器的响应,基本上遵循real-world示例。这种方式entities
reducer非常简单,只需合并响应即可。我现在遇到的问题是delete
操作。我发现了这个issue#21 of normalizr repo,但仍然无法弄清楚如何解决这个问题。例如,
当前状态是
{
entities:
product_categories: {
...
13: {
...
products: ["1", "2"], <--------------- [i] Current state
...
}
},
products: {
1: {
id: "1"
}
}
}
标准化响应是
{
...
product_categories: {
...
13: {
...
products: ["1"], <---------------- [2] Normalized result
}
...
}
如您所见,后端api只返回属于此类别的所有产品ID ,在这种情况下,“2”已分离。当'entities'reducer合并这个响应时,“2”仍然存在。现在我只是重新加载页面,但我想知道是否有更好的方法来处理这种情况?
在entities
reducer中,我只是像在现实世界中一样合并它。
return merge({}, state, action.payload.entities);
答案 0 :(得分:11)
不要担心它在那里。将您的状态视为数据库。您不能真正从数据库中删除记录,以避免复杂的级联 - 通常您只需更改其在数据库中的状态。类似地,使用Normalizer,而不是真正删除实体,让它们在缓存中,直到用户离开页面!
答案 1 :(得分:0)
以下是对我的解决方案的解释,然后是代码。
要执行删除,我已将我的reducer更新为处理删除操作:REMOVE_ENTITY_ITEM
。在操作中,我传递了要删除的实体的id
和name
。
在reducer中,我首先删除store.entities[entityName][entityId]
处的实体本身。接下来我需要从可能引用它的所有其他实体中删除它的id
。由于我使用normalizr
我的所有实体都是扁平的,如果它们引用另一个实体,那么它们只会在数组中有它的id。这使得删除引用相对简单。我只是循环遍历所有实体并过滤掉对要删除的实体的引用。
我将此方法与#1的其他两种方法结合使用。)刷新应用程序/状态和#2。)翻转实体状态位而不是删除然后过滤UI中关闭的项目。这些方法已得到很好的讨论here
const entities = (state={}, action) => {
if(action.payload && action.payload.entities) {
return merge( {} , state, action.payload.entities);
}else{
return deleteHandlingReducer(state, action)
}
}
const deleteHandlingReducer = (state=initialSate, action) => {
switch(action.type){
case "REMOVE_ENTITY_ITEM":
if (!action.meta || !action.meta.name || !action.meta.id) {
return state;
}else{
let newState = Object.assign({}, state);
if(newState[action.meta.name]){
delete newState[action.meta.name][action.meta.id];
Object.keys(state).map(key => {
let entityHash = state[key];
Object.keys(entityHash).map(entityId => {
let entity = entityHash[entityId];
if(entity[action.meta.name] &&
Array.isArray(entity[action.meta.name])){
entity[action.meta.name] = entity[action.meta.name].
filter(item => item != action.meta.id)
}
});
})
}
return newState;
}
default:
return state;
}
}
现在要删除我发起这样的动作:
store.dispatch({
type: "REMOVE_ENTITY_ITEM",
meta: {
id: 1,
name: "job_titles"
}
});
答案 2 :(得分:0)
使用lodash assign。如果使用合并将无法正常工作。
示例:
const object = {
'a': [1,2,3]
}
const other = {
'a': [1,2]
}
// item 3 was not removed
const merge = _.merge({}, object, other)
console.log(merge) // {'a': [1,2,3]}
// item 3 was removed
const assign = _.assign({}, object, other)
console.log(assign) // {'a': [1,2]}
&#13;
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.5/lodash.min.js"></script>
&#13;
在这里,您的代码将如何显示
// state
const state = {
entities: {
product_categories: {
'1': {
id: 1,
products: [1,2]
}
},
products: {
'1': {
id: 1
},
'2': {
id: 2
}
}
}
}
// example of action
// normalized by normalizr
const action = {
type: 'REMOVE_PRODUCT_CATEGORY_SUCCESS',
payload: {
entities: {
product_categories: {
'1': {
id: 1,
products: [1]
}
}
}
}
}
// product_categories entity reducer
function productCategoriesEntityReducer (state = {}, action) {
switch (action.type) {
default:
if (_.has(action, 'payload.entities.product_categories')) {
return _.assign({}, state, action.payload.entities.product_categories)
}
return state
}
}
// run reducer on state.entities.product_categories
const newState = productCategoriesEntityReducer(state.entities.product_categories, action);
console.log(newState)
&#13;
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.5/lodash.min.js"></script>
&#13;