1. Immutability-helper 修改 nested array of objects

1.1. 一次操作,只修改某个内嵌 object 的字段

原数组

const products = [
  {
    id: '111',
    analysis: [{ id: 1, value: 0 }, { id: 2, value: 0 }, { id: 3, value: 0 }],
  },
  {
    id: '222',
    analysis: [{ id: 1, value: 0 }, { id: 2, value: 0 }, { id: 3, value: 0 }],
  },
];

操作:根据 productId 和 analysisId 找到 nested object, 只更新他的 value

const action = { id: '111', analysisId: 2, value: 99 };

处理代码:使用 immutability-helper 时需要找到要更新 object 在 array 中的 index。如上面 id=111 对应 index=0,analysisId=2 对应 index=1

const newProducts = update(products, {
  0: {
    analysis: {
      1: { $merge: { value: 99 } },
      // 0: { $merge: { value: 99 }}  // 可以一次性更新多个操作,这里只是举例
    },
  },
});

结果

const newProducts = [
            {
                id: '111',
                analysis: [
                    { id: 1, value: 0 },
-                    { id: 2, value: 0 },
+                    { id: 2, value: 99 },
                    { id: 3, value: 0 }
            },
            {
                id: '222',
                analysis: [
                    { id: 1, value: 0 },
                    { id: 2, value: 0 },
                    { id: 3, value: 0 }
                ]
            }
        ]

1.1.1. 如何根据 id 找到 对应的 index

const targetProductIndex = products.findIndex((x) => x.id === action.id);
const targetProduct = products.find((x) => x.id === action.id);
const targetAnalysisIndex = targetProduct.analysis.findIndex((x) => x.id === action.analysisId);
const targetAnalysis = targetProduct.analysis.find((x) => x.id === action.analysisId);

const result = update(products, {
  [targetProductIndex]: {
    analysis: {
      [targetAnalysisIndex]: { $merge: { value: action.value } },
    },
  },
});

1.2. 多次操作

const actionArr = [
  { id: '111', analysisId: 1, value: 99 },
  { id: '111', analysisId: 3, value: 99 },
  { id: '222', analysisId: 3, value: 99 },
];

以上意味着 3 次操作。第一次找到 productId=111,再找到 analysisId=1,更新他 value 从 0 到 99。剩下两次操作类似。

经过操作后 products 的结果:

const newProducts = [
            {
                id: '111',
                analysis: [
-                    { id: 1, value: 0 },
+                    { id: 3, value: 99 },
                     { id: 2,  value: 0 },
-                    { id: 3, value: 0, },
+                    { id: 3, value: 99 }
                ]
            },
            {
                id: '222',
                analysis: [
                     { id: 1, value: 0 },
                     { id: 2,  value: 0 },
-                    { id: 3, value: 0 },
+                    { id: 3, value: 99, },
                ]
            }
        ]

处理代码

const newProducts = update(products, {
  0: {
    analysis: {
      0: { $merge: { value: 99 } },
      2: { $merge: { value: 99 } },
    },
  },
  1: {
    analysis: {
      2: { $merge: { value: 99 } },
    },
  },
});

1.2.1. 如何根据 actionArr 构建 update 语句

思路 1:每循环 actionArr 一次时,进行一次 update 操作,返回第一次操作后的结果,作为第二次 update 的对象。依次,所以用 reduce。但这样多次复制对象,不太好

多个循环积累更新

const actionArr = [
  { id: '111', analysisId: 1, value: 99 },
  { id: '111', analysisId: 3, value: 99 },
  { id: '222', analysisId: 3, value: 99 },
];

// acc 每次操作积累的结果,cur 是 actionArr 循环中当前对象。首次 acc = products
const result = actionArr.reduce((acc, cur) => {
  const targetIndex = acc.findIndex((x) => x.id === cur.id);
  const target = acc.find((x) => x.id === cur.id);
  const targetAnalysisIndex = target.analysis.findIndex((x) => x.id === cur.analysisId);
  const targetAnalysis = target.analysis.find((x) => x.id === cur.analysisId);

  return update(acc, {
    [targetIndex]: {
      analysis: {
        [targetAnalysisIndex]: { $merge: { value: cur.value } },
      },
    },
  });
}, products);

思路 2:循环构建好 update 语句中的对象,之后一次性更新

const buildUpdateOperation = (source, actionArr) => {
  let result = {};

  actionArr.forEach((action) => {
    const targetIndex = source.findIndex((x) => x.id === action.id);
    const target = source.find((x) => x.id === action.id);
    const targetAnalysisIndex = target.analysis.findIndex((x) => x.id === action.analysisId);
    const targetAnalysis = target.analysis.find((x) => x.id === action.analysisId);

    if (result[targetIndex]) {
      // 第二次更新同一个 product,但 analysisId 不同
      result[targetIndex].analysis[targetAnalysisIndex] = { $merge: { value: action.value } };
    } else {
      // 首次不存在 index,赋值
      result[targetIndex] = {
        analysis: {
          [targetAnalysisIndex]: { $merge: { value: c.value } },
        },
      };
    }
  });

  return result;
};

生成的结果为

{
  0: {
    analysis: {
      0: { $merge: { value: 99 } },
      2: { $merge: { value: 99 } }
    }
  },
  1: {
    analysis: {
      2: { $merge: { value: 99 } }
    }
  }
}

一次行更新

const updateQuery = buildUpdateOperation(products, actionArr);
const newProducts = update(products, updateQuery);
Copyright © Guanghui Wang all right reserved,powered by GitbookFile Modified: 2019-08-25 13:56:34

results matching ""

    No results matching ""