首页 > 解决方案 > 如何在反应中深度更新递归嵌套的对象数组

问题描述

[
   {
       "id": 339,
       "children": [
           {
               "id": 381,
               "children": [
                   {
                       "id": 383,
                       "children": [],
                       "name": "Capability_C",
                       "level": 3,
                   }
               ],
               "name": "Capability_B",
               "level": 2,
           }
       ],
       "name": "Capability_A",
       "level": 1,
   }

] 

我如何在我的减速器中正确更新这个嵌套对象(状态有这些对象的列表,而有效负载有一个可以是嵌套对象的特定对象

        return [...state, payload];

标签: reactjsreact-redux

解决方案


数据结构的递归性使得这是一项不平凡的任务。您需要一种方法来进入它,处理错误的路径,并为您更新的任意深度动态克隆您的状态。

您需要一个看起来像这样的操作,其中路径数组是一个 id 编号列表,可让您进入数据:

{
  type: "CREATE_CAPABILITY";
  payload: {
    path: Array<number>;
    capability: CapabilityObject;
  }
}

然后在你的 reducer 中,将此操作传递给与当前 reducer 状态一起的递归函数:

// function

const insertCapability = (state, action) => {
  const { path, capability } = action.payload;

  if (path.length === 0) return [...state, capability];

  const nextId = path.shift();
  const childIdx = state.findIndex(cap => cap.id === nextId);

  if (childIdx < 0) return state;

  const nextChild = {
    ...state[childIdx],
    children: insertCapability(state[childIdx].children, action)
  }
  
  return (s => {s[childIdx] = nextChild; return s;})([...state]);
};

// test case

const state = [
   {
       "id": 339,
       "children": [
           {
               "id": 381,
               "children": [
                   {
                       "id": 383,
                       "children": [],
                       "name": "Capability_C",
                       "level": 3,
                   }
               ],
               "name": "Capability_B",
               "level": 2,
           }
       ],
       "name": "Capability_A",
       "level": 1,
   }
];

const action = {
  type: "CREATE_CAPABILITY",
  payload: {
    path: [339, 381, 383],
    capability: {
      id: 400,
      children: [],
      name: "New Capability",
      level: 4, 
    }
  }
}

console.log(insertCapability(state, action));

请注意,每次状态都返回新数据时,它是在一个新数组中完成的[...state]- 并且每个路径进入的新子节点也被克隆 - ...state[childIdx]。这样做很重要,这样您的状态结构才能保持不变。未能正确克隆状态并意外地对其进行变异可能会在以后导致一些丑陋的错误。


推荐阅读