使用 Javascript/Lodash 替换 Redux Store 中对象数组中的对象
Replacing an object in an object array in Redux Store using Javascript/Lodash
我在 reducer 中有一个对象数组,如下所示:
[
{id:1, name:Mark, email:mark@email.com},
{id:2, name:Paul, email:paul@gmail.com},
{id:3,name:sally, email:sally@email.com}
]
下面是我的减速器。到目前为止,我可以通过以下方式向 currentPeople
reducer 添加一个新对象:
const INITIAL_STATE = { currentPeople:[]};
export default function(state = INITIAL_STATE, action) {
switch (action.type) {
case ADD_PERSON:
return {...state, currentPeople: [ ...state.currentPeople, action.payload]};
}
return state;
}
但这就是我卡住的地方。我可以使用 lodash 通过 reducer 更新一个人吗?
如果我发送一个看起来像这样的动作负载:
{id:1, name:Eric, email:Eric@email.com}
我可以用新字段替换 ID 为 1 的对象吗?
这是数据规范化的一个很好的候选者。如果在将数据存储到状态树之前对其进行规范化,则可以有效地用新数据替换数据。
此示例直接来自 Normalizr。
[{
id: 1,
title: 'Some Article',
author: {
id: 1,
name: 'Dan'
}
}, {
id: 2,
title: 'Other Article',
author: {
id: 1,
name: 'Dan'
}
}]
可以这样归一化-
{
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
},
users: {
1: {
id: 1,
name: 'Dan'
}
}
}
}
归一化有什么好处?
您可以提取您想要的状态树的确切部分。
例如-您有一个对象数组,其中包含有关文章的信息。如果您想 select 该数组中的特定对象,则必须遍历整个数组。最坏的情况是数组中不存在所需的对象。为了克服这个问题,我们将数据标准化。
要规范化数据,请将每个对象的唯一标识符存储在单独的数组中。我们将该数组称为 results
.
result: [1, 2, 3 ..]
并将对象数组转换为具有键的对象作为id
(参见第二个片段)。将该对象称为 entities
.
最终,要使用 id
1 访问对象,只需执行此操作 - entities.articles["1"]
。
如果你想用新数据替换旧数据,你可以这样做-
entities.articles["1"] = newObj;
是的,您完全可以根据需要更新数组中的对象。如果你不想的话,你不需要改变你的数据结构。您可以将这样的案例添加到您的减速器中:
case UPDATE_PERSON:
return {
...state,
currentPeople: state.currentPeople.map(person => {
if (person.id === action.payload.id) {
return action.payload;
}
return person;
}),
};
这也可以缩短,使用隐式 returns 和三元:
case UPDATE_PERSON:
return {
...state,
currentPeople: state.currentPeople.map(person => (person.id === action.payload.id) ? action.payload : person),
};
Mihir 关于使用 normalizr 将数据映射到对象的想法当然是可能的,从技术上讲,使用引用更新用户而不是执行循环(在完成初始映射后)会更快。但是如果你想保留你的数据结构,这种方法会奏效。
此外,像这样的映射只是更新对象的众多方法之一,并且需要浏览器支持 Array.prototype.map()。你可以使用 lodash indexOf() 来找到你想要的用户的索引(这很好,因为它在成功时打破了循环,而不是像 .map 那样继续),一旦你有了索引,你就可以覆盖对象直接使用它的索引。确保你没有改变 redux 状态,如果你想像这样分配,你需要在克隆上工作:clonedArray[foundIndex] = action.payload;
.
使用数组原生拼接方式:
/*Find item index using lodash*/
var index = _.indexOf(currentPeople, _.find(currentPeople, {id: 1}));
/*Replace item at index using splice*/
arr.splice(index, 1, {id:1, name:'Mark', email:'mark@email.com'});
我在 reducer 中有一个对象数组,如下所示:
[
{id:1, name:Mark, email:mark@email.com},
{id:2, name:Paul, email:paul@gmail.com},
{id:3,name:sally, email:sally@email.com}
]
下面是我的减速器。到目前为止,我可以通过以下方式向 currentPeople
reducer 添加一个新对象:
const INITIAL_STATE = { currentPeople:[]};
export default function(state = INITIAL_STATE, action) {
switch (action.type) {
case ADD_PERSON:
return {...state, currentPeople: [ ...state.currentPeople, action.payload]};
}
return state;
}
但这就是我卡住的地方。我可以使用 lodash 通过 reducer 更新一个人吗? 如果我发送一个看起来像这样的动作负载:
{id:1, name:Eric, email:Eric@email.com}
我可以用新字段替换 ID 为 1 的对象吗?
这是数据规范化的一个很好的候选者。如果在将数据存储到状态树之前对其进行规范化,则可以有效地用新数据替换数据。
此示例直接来自 Normalizr。
[{
id: 1,
title: 'Some Article',
author: {
id: 1,
name: 'Dan'
}
}, {
id: 2,
title: 'Other Article',
author: {
id: 1,
name: 'Dan'
}
}]
可以这样归一化-
{
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
},
users: {
1: {
id: 1,
name: 'Dan'
}
}
}
}
归一化有什么好处?
您可以提取您想要的状态树的确切部分。
例如-您有一个对象数组,其中包含有关文章的信息。如果您想 select 该数组中的特定对象,则必须遍历整个数组。最坏的情况是数组中不存在所需的对象。为了克服这个问题,我们将数据标准化。
要规范化数据,请将每个对象的唯一标识符存储在单独的数组中。我们将该数组称为 results
.
result: [1, 2, 3 ..]
并将对象数组转换为具有键的对象作为id
(参见第二个片段)。将该对象称为 entities
.
最终,要使用 id
1 访问对象,只需执行此操作 - entities.articles["1"]
。
如果你想用新数据替换旧数据,你可以这样做-
entities.articles["1"] = newObj;
是的,您完全可以根据需要更新数组中的对象。如果你不想的话,你不需要改变你的数据结构。您可以将这样的案例添加到您的减速器中:
case UPDATE_PERSON:
return {
...state,
currentPeople: state.currentPeople.map(person => {
if (person.id === action.payload.id) {
return action.payload;
}
return person;
}),
};
这也可以缩短,使用隐式 returns 和三元:
case UPDATE_PERSON:
return {
...state,
currentPeople: state.currentPeople.map(person => (person.id === action.payload.id) ? action.payload : person),
};
Mihir 关于使用 normalizr 将数据映射到对象的想法当然是可能的,从技术上讲,使用引用更新用户而不是执行循环(在完成初始映射后)会更快。但是如果你想保留你的数据结构,这种方法会奏效。
此外,像这样的映射只是更新对象的众多方法之一,并且需要浏览器支持 Array.prototype.map()。你可以使用 lodash indexOf() 来找到你想要的用户的索引(这很好,因为它在成功时打破了循环,而不是像 .map 那样继续),一旦你有了索引,你就可以覆盖对象直接使用它的索引。确保你没有改变 redux 状态,如果你想像这样分配,你需要在克隆上工作:clonedArray[foundIndex] = action.payload;
.
使用数组原生拼接方式:
/*Find item index using lodash*/
var index = _.indexOf(currentPeople, _.find(currentPeople, {id: 1}));
/*Replace item at index using splice*/
arr.splice(index, 1, {id:1, name:'Mark', email:'mark@email.com'});