在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的片断需要更新和需要作出的变化。

例如,如果某个操作具有idlink属性,并且您希望将该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例子来演示这种方法。