What's the best/correct way to update a nested array of data in a store using redux?
使用redux更新商店中嵌套数据的最佳/正确方法是什么?
My store looks like this:
我的商店看起来像这样:
{
items:{
1: {
id: 1,
key: "value",
links: [
{
id: 10001
data: "some more stuff"
},
...
]
},
...
}
}
I have a pair of asynchronous actions that updates the complete items
object but I have another pair of actions that I want to update a specific links
array.
我有一对异步操作来更新完整的项目对象,但我有另一对我想要更新特定链接数组的操作。
My reducer currently looks like this but I'm not sure if this is the correct approach:
我的减速机目前看起来像这样,但我不确定这是否是正确的方法:
switch (action.type) {
case RESOURCE_TYPE_LINK_ADD_SUCCESS:
// TODO: check whether the following is acceptable or should we create a new one?
state.items[action.resourceTypeId].isSourceOf.push(action.resourceTypeLink);
return Object.assign({}, state, {
items: state.items,
});
}
2 个解决方案
#1
49
React's update()
immutability helper is a convenient way to create an updated version of a plain old JavaScript object without mutating it.
React的update()immutability helper是一种创建普通旧JavaScript对象的更新版本而不会改变它的便捷方式。
You give it the source object to be updated and an object describing paths to the pieces which need to be updated and changes that need to be made.
您可以为其提供要更新的源对象,以及描述需要更新的部分的路径的对象以及需要进行的更改。
e.g., if an action had id
and link
properties and you wanted to push the link
to an array of links in an item keyed with the id
:
例如,如果某个操作具有id和链接属性,并且您希望将链接推送到以id键入的项目中的链接数组:
var update = require('react/lib/update')
// ...
return update(state, {
items: {
[action.id]: {
links: {$push: action.link}
}
}
})
(Example uses an ES6 computed property name for action.id
)
(示例使用action.id的ES6计算属性名称)
#2
57
Jonny's answer is correct (never mutate the state given to you!) but I wanted to add another point to it. If all your objects have IDs, it's generally a bad idea to keep the state shape nested.
Jonny的回答是正确的(永远不会改变给你的状态!)但我想补充一点。如果所有对象都有ID,那么保持状态嵌套通常是个坏主意。
This:
这个:
{
items: {
1: {
id: 1,
links: [{
id: 10001
}]
}
}
}
is a shape that is hard to update.
是一种难以更新的形状。
It doesn't have to be this way! You can instead store it like this:
它不一定是这样!你可以这样存储它:
{
items: {
1: {
id: 1,
links: [10001]
}
},
links: {
10001: {
id: 10001
}
}
}
This is much easier for update because there is just one canonical copy of any entity. If you need to let user “edit a link”, there is just one place where it needs to be updated—and it's completely independent of items
or anything other referring to links
.
这更容易更新,因为只有一个任何实体的规范副本。如果您需要让用户“编辑链接”,则只需要更新一个地方 - 它完全独立于项目或其他任何引用链接的地方。
To get your API responses into such a shape, you can use normalizr. Once your entities inside the server actions are normalized, you can write a simple reducer that merges them into the current state:
要将API响应变为这样的形状,可以使用normalizr。一旦您的服务器操作中的实体被规范化,您就可以编写一个简单的reducer,将它们合并到当前状态:
import merge from 'lodash/object/merge';
function entities(state = { items: {}, links: {} }, action) {
if (action.response && action.response.entities) {
return merge({}, state, action.response.entities);
}
return state;
}
Please see Redux real-world
example for a demo of such approach.
有关此类方法的演示,请参阅Redux实际示例。
#1
49
React's update()
immutability helper is a convenient way to create an updated version of a plain old JavaScript object without mutating it.
React的update()immutability helper是一种创建普通旧JavaScript对象的更新版本而不会改变它的便捷方式。
You give it the source object to be updated and an object describing paths to the pieces which need to be updated and changes that need to be made.
您可以为其提供要更新的源对象,以及描述需要更新的部分的路径的对象以及需要进行的更改。
e.g., if an action had id
and link
properties and you wanted to push the link
to an array of links in an item keyed with the id
:
例如,如果某个操作具有id和链接属性,并且您希望将链接推送到以id键入的项目中的链接数组:
var update = require('react/lib/update')
// ...
return update(state, {
items: {
[action.id]: {
links: {$push: action.link}
}
}
})
(Example uses an ES6 computed property name for action.id
)
(示例使用action.id的ES6计算属性名称)
#2
57
Jonny's answer is correct (never mutate the state given to you!) but I wanted to add another point to it. If all your objects have IDs, it's generally a bad idea to keep the state shape nested.
Jonny的回答是正确的(永远不会改变给你的状态!)但我想补充一点。如果所有对象都有ID,那么保持状态嵌套通常是个坏主意。
This:
这个:
{
items: {
1: {
id: 1,
links: [{
id: 10001
}]
}
}
}
is a shape that is hard to update.
是一种难以更新的形状。
It doesn't have to be this way! You can instead store it like this:
它不一定是这样!你可以这样存储它:
{
items: {
1: {
id: 1,
links: [10001]
}
},
links: {
10001: {
id: 10001
}
}
}
This is much easier for update because there is just one canonical copy of any entity. If you need to let user “edit a link”, there is just one place where it needs to be updated—and it's completely independent of items
or anything other referring to links
.
这更容易更新,因为只有一个任何实体的规范副本。如果您需要让用户“编辑链接”,则只需要更新一个地方 - 它完全独立于项目或其他任何引用链接的地方。
To get your API responses into such a shape, you can use normalizr. Once your entities inside the server actions are normalized, you can write a simple reducer that merges them into the current state:
要将API响应变为这样的形状,可以使用normalizr。一旦您的服务器操作中的实体被规范化,您就可以编写一个简单的reducer,将它们合并到当前状态:
import merge from 'lodash/object/merge';
function entities(state = { items: {}, links: {} }, action) {
if (action.response && action.response.entities) {
return merge({}, state, action.response.entities);
}
return state;
}
Please see Redux real-world
example for a demo of such approach.
有关此类方法的演示,请参阅Redux实际示例。