【问题标题】:React: Reaching Nested State Items w/ ReducerReact:使用 Reducer 访问嵌套状态项
【发布时间】:2019-09-09 10:24:01
【问题描述】:

我正在处理一些深度嵌套的状态对象,感谢 SO 社区的大量智慧,have switched 使用Reducer 来管理状态。我无法弄清楚到达深度嵌套项或数组中连续对象的语法。这是我的状态对象:

 const initialState = {
    customer: [
      {
        name: "Bob",
        address: "1234 Main Street",
        email: "bob@mail.com",
        phone: [
          {
            mobile: "555-5555",
            home: "555-5555"
          }
        ]
      },
      {
        name: "Reggie",
        address: "5555 Pineapple Lane",
        email: "reggie@mail.com",
        phone: [
          {
            mobile: "123-4567",
            home: {
              fax: "444-4444",
              evening: "222-2222"
              }
          }
        ]
      }
    ]
  }

我需要联系我们的第二位客户 Reggie,并更改他的地址和晚上回家的电话号码(customer[1].address & customer[1].phone[1].home.evening)

我已经用我的 useReducer 案例语句尝试过这个,但没有运气。 . .当我调用这些函数时,我得到一个TypeError: Cannot read property 'object' of undefined(大概是从我的下拉菜单中,谁的值设置为我要更改的这个道具):

    case "SET_CUST1_ADDRESS":
      return {
        ...state,
        customer: [
          { ...state.customer[1], address: value }
        ]
      };

     onChange={({ target: { value } }) =>
                dispatch({ type: "SET_CUST1_ADDRESS", value })
              }

第二个是晚上的号码。 . .

    case "SET_CUST1_PHONE_HOME_EVENING":
      return {
        ...state,
        customer: [
          {
            ...state.customer[1],
            phone: [
              {
                ...state.customer[1].phone[0],
                home: {
                  ...state.customer[1].phone[0].home,
                  evening: value
                }
              }
            ]
          }
        ]
      };

    onChange={({ target: { value } }) =>
                dispatch({ type: "SET_CUST1_PHONE_HOME_EVENING", value 
   })
   }

我知道需要使用扁平状态对象来简化这一切,但不幸的是,我使用的数据结构是不可变的。欢迎提示/技巧/cmets。谢谢!

更新:

似乎在使用这两个 case 语句之间存在未解决的冲突,这导致我在状态更改期间出现TypeError: Cannot read property 'object' of undefined。当我尝试更改同一数组中两个不同数组对象的状态时,出现错误。显然这两种情况不能同时存在:

case "SET_CUST_ADDRESS":
            return {
        ...state,
        customer: [
          { ...state.customer[0], address: value }
        ]
      };

    case "SET_CUST1_ADDRESS":
      return {
        ...state,
        customer: [
          state.customer[0],
          { ...state.customer[1], address: value }
        ]
      };

当我在其中一个 or 上调用下拉函数时,这两个 case 语句似乎相互导致错误,从而导致上述错误。我没有看到联系。任何进一步的意见将不胜感激。

【问题讨论】:

    标签: json reactjs events nested state


    【解决方案1】:

    如果我理解你的问题,你会错过这一行:

    case "SET_CUST1_PHONE_HOME_EVENING":
          return {
            ...state,
            customer: [
              state.customer[0],
              {
                ...state.customer[1],
                phone: [
                  {
                    ...state.customer[1].phone[0],
                    home: {
                      ...state.customer[1].phone[0].home,
                      evening: value
                    }
                  }
                ]
              }
            ]
          };
    

    我的意思是您忘记将 customer[0] 再次插入状态。

    如果这没有帮助 - 您可以尝试控制台记录之前和之后的状态并查看您不想要哪些更改 - 以及需要根据该更改修复哪些代码。

    编辑: 你可以使用这样的东西:

    const stateCustomers = state.customer.slice();
    let customer = stateCustomers.find(c => <your condition to find the desired customer>);
    customer.phone[0].home.evening = value;
    return {
       ...state,
       customer: stateCustomers
    };
    

    【讨论】:

    • 第一个 state.customer[0] 应该像其他的一样传播吗?
    • 另外,如果我是第三个客户怎么办?我需要同时包含 state.customer[0] 和 state.customer[1] 吗?那会是什么样子?再次感谢@NNH 的帮助
    • 我明白了,非常感谢。 . .你看到我关于第三位客户的笔记了吗?我将如何像您在上面那样包含它?
    • 如果您使用我建议的第二种方式,那么您无需担心其他客户。如果您仍然想使用您的方式,那么可以,您必须担心该州的其他客户。
    • 我能想到的另一个想法是通过键来保留客户,例如:customerID 然后您的状态将如下所示: state: {customer: 1: {...customerDetails}, 2: {...customerDetails}} 这样您就可以通过它的 id 只更改您需要的客户。
    【解决方案2】:

    更新:

    如果有人遇到类似问题并且难以处理嵌套项,我建议首先阅读state immutability,正如我在reddit thread 中向我推荐的那样。

    我还(通过推荐)发现了一种通过称为 immer 的东西来处理这种嵌套状态的超级方法。这就像创建一个 import 语句然后将您的 case 语句包装在一个“生产”函数中一样简单,这会生成您可以直接引用的状态草稿,而不是分散所有层来进行更改。所以,不要有这样的东西:

    case "SET_CUST1_PHONE_HOME_EVENING":
          return {
            ...state,
            customer: [
              state.customer[0],
              {
                ...state.customer[1],
                phone: [
                  {
                    ...state.customer[1].phone[0],
                    home: {
                      ...state.customer[1].phone[0].home,
                      evening: value
                    }
                  }
                ]
              }
            ]
          };
    

    你可以改用这样的东西,IMO 更干净,更容易读/写:

        import { produce } from 'immer';
        ...
    
        case "SET_CUST1_PHONE_HOME_EVENING":
          return produce(state, draft => {
            draft.customer[1].phone[0].home.evening = value
          });
    

    然后繁荣!你已经完成了。

    【讨论】:

      猜你喜欢
      • 2017-08-08
      • 2017-04-02
      • 2017-12-31
      • 2018-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-07
      • 2020-05-30
      相关资源
      最近更新 更多