在redux存储中更新嵌套的数据
使用redux更新商店中嵌套数据的最佳/正确方法是什么?
我的店看起来像这样:
{ items:{ 1: { id: 1, key: "value", links: [ { id: 10001 data: "some more stuff" }, ... ] }, ... } }
我有一对asynchronous操作更新完整的items
对象,但我有另一对行动,我想更新特定的links
数组。
我的减速机目前看起来像这样,但我不知道这是否是正确的方法:
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, }); }
React的update()
不变性帮助器是一种方便的方式来创build一个普通的旧JavaScript对象的更新版本,而不会改变它。
你给它的源对象进行更新和一个对象描述path的片断需要更新和需要作出的变化。
例如,如果某个操作具有id
和link
属性,并且您希望将该link
推送到与id
绑定的项目中的链接数组:
var update = require('react/lib/update') // ... return update(state, { items: { [action.id]: { links: {$push: action.link} } } })
(示例使用ES6计算的属性名称作为action.id
)
强尼的回答是正确的(不要改变给你的状态!),但我想补充一点。 如果所有的对象都有ID,那么保持嵌套状态通常是一个坏主意。
这个:
{ items: { 1: { id: 1, links: [{ id: 10001 }] } } }
是一个难以更新的形状。
它不一定是这样的! 您可以改为像这样存储它:
{ items: { 1: { id: 1, links: [10001] } }, links: { 10001: { id: 10001 } } }
这更容易更新,因为任何实体只有一个规范的副本。 如果您需要让用户“编辑一个链接”,那么只需要一个地方来更新它,而且它完全独立于items
或任何其他指向links
。
为了让你的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; }
请参阅Redux real-world
例子来演示这种方法。