【问题标题】:Redux store immutable pattern for nested data in array?Redux 为数组中的嵌套数据存储不可变模式?
【发布时间】:2020-09-29 22:35:28
【问题描述】:

我有一个简单的 JSON 数据数组,看起来像这样(在我的 Redux 存储中也是一样,我将它存储在 properties 下):

[
  {
    "id": "room",
    "name": "Room",
    "description": "Just a room",
    "foo": "bar",
  },
  {
    "id": "apartment",
    "name": "Apartment",
    "description": "just an apartment",
    "foo": "bar",
  }
]

它必须是一个数组,因为我正在映射它:

{properties.map(property => 
  <Property 
    id={property.id} 
    name={property.name} 
    description={property.description} 
    foo={property.foo}
 />)}

这样我的应用程序中呈现了两个属性。

问题是 - 我如何在 Redux 中更新 "foo"

这是我目前的减速机written according to the docs:

case 'UPDATE_FOO':
  return {
    ...state, 
    properties: {
      ...state.properties,
      [action.id]: {
      ...state.properties[action.id],
      foo: action.fooData,
    }
  }
}

当然它会抛出TypeError: Cannot read property 'room' of undefined,因为我正在尝试访问state.properties["room"],但它不存在。

我一直在考虑重塑我的 JSON 和 Redux 存储,但是一旦我将其更改为命名对象,我就无法对其进行映射...

谢谢!

【问题讨论】:

    标签: javascript arrays json reactjs redux


    【解决方案1】:

    将您的商店更改为对象,并在需要渲染时生成数组,方法是将其转换为数组,使用Object.values()

    {Object.values(properties).map(property => (
      <Property key={property.id} {...property} />
    )}
    

    如果订单可能发生变化(例如排序),您需要另一个带有 id 的数组来保存订单(请参阅redux normalized state):

    {
      properties: {
        room: {
          "id": "room",
          "name": "Room",
          "description": "Just a room",
          "foo": "bar",
        },
        apartment: {
          "id": "apartment",
          "name": "Apartment",
          "description": "just an apartment",
          "foo": "bar",
        }
      }
    }
    
    {
      properties: {
        room: {
          "id": "room",
          "name": "Room",
          "description": "Just a room",
          "foo": "bar",
        },
        apartment: {
          "id": "apartment",
          "name": "Apartment",
          "description": "just an apartment",
          "foo": "bar",
        }
      },
      order: ['apartment', 'room']
    }
        
    {order.map(id => (
      <Property key={id} {...properties[id]} />
    )}
    

    【讨论】:

    • 可能值得指出的是,Property 的渲染可以缩短为 Object.values(properties).map(property =&gt; &lt;Property key={property.id} {...property}/&gt;)
    • 我真的很喜欢你的回答,但是使用格式如下的 JSON 设置商店:const initialState = { myJsonData} 最终会得到state.properties.properties,它为我的减速器增加了另一个层次,对吗? :(
    • 不——只是state.properties。数组properties 被替换为对象properties
    • @OriDrori 嗯,那我一定是做错了什么,但我认为“属性”是从 JSON 文件拖到这里的:imgur.com/a/FECwFCq。如果我用const initialState = {properties: myJsonData}const initialState = {myJsonData} 初始化存储无关紧要,我总是把它翻倍:[
    • 您需要在插入 JSON 时对其进行规范化,这意味着您需要对其进行迭代,并在 reducer 中创建状态的形状。
    【解决方案2】:

    如果您想使用 ID 更新商店。您可以使用 id 在属性数组中查找一个元素(您正在尝试编辑),然后对其进行更新:

        case 'UPDATE_FOO':
            const newProperties = state.properties.map(property => {
                if(property.id === action.id) {
                    return { ...property, foo: action.fooData}
                }
                return property;
            })
            return {
                ...state,
                properties: newProperties
            }
         }
    

    【讨论】:

    • 这很棒,但很难阅读和理解 :( 我想我至少应该使用 immer 吗?它是一个扁平的 JSON 并且仍然像这样更新一个 prop 看起来很疯狂。
    猜你喜欢
    • 2020-02-08
    • 2015-11-15
    • 1970-01-01
    • 2019-06-17
    • 2012-04-04
    • 2018-02-06
    • 2017-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多