更新多个嵌套对象

时间:2020-04-22 13:10:14

标签: javascript ecmascript-6

我有嵌套的对象,并且在传入更改时,我想创建费用对象的副本并更新所有timeSpent值。新值是根据更新后的数据计算得出的,因此我必须对每个timeSpent值进行计算。我找不到解决办法。

我已经厌倦了使用{... expenses.byId}创建费用对象的副本,并使用Ovject.values从中创建数组,映射数据并进行计算。然后问题出现了,值被嵌套,所以原始对象被更改了。

我很累于制作对象的深层副本,问题是否相同或我做错了什么。如果我需要在copyOfExpenses中更深入一点,该怎么做?

 const state = {
    expenses: {
        byId: {
            k948zpnp: {
                id: 'k948zpnp',
                category: 'other',
                description: 'book',
                amount: '25',
                timeSpent: '2.5',
                time: '2020-4-21 10:48:10'
            },
            z9e8ipnp: {
                id: 'z9e8ipnp',
                category: 'food',
                description: 'pasta',
                amount: '12',
                timeSpent: '1.2',
                time: '2020-4-21 11:48:10'
            },
        },
        allIds: ['k948zpnp', 'z9e8ipnp']
    }
}

const copyOfExpenses = {
    ...state,
    expenses: {
        ...state.expenses,
        byId: { ...state.expenses.byId },
        allIds: [...state.expenses.allIds]
    }
}

let newInputForTimeSpent = 14
let newData = copyOfExpenses.expenses.allIds.map(
    item =>
        (copyOfExpenses.expenses.byId[item].timeSpent =
            copyOfExpenses.expenses.byId[item].timeSpent * newInputForTimeSpent)
)

console.log(copyOfExpenses) // changes works
console.log(state) // original data gets changed

1 个答案:

答案 0 :(得分:1)

第一种方法

我知道,对ID进行硬编码是一个糟糕的主意。

let newInputForTimeSpent = 14;

const copyOfExpenses = {
    ...state,
    expenses: {
        ...state.expenses,
        byId: {
           ...state.expenses.byId,
           k948zpnp: {
             ...state.expenses.k948zpnp,
             timeSpent: state.expenses.k948zpnp.timeSpent * newInputForTimeSpent
           },
           z9e8ipnp: {
             ...state.expenses.z9e8ipnp,
             timeSpent: state.expenses.z9e8ipnp.timeSpent * newInputForTimeSpent 
           }
        },
        allIds: [...state.expenses.allIds]
    }
}

第二种方法

const state = {
  expenses: {
    byId: {
      k948zpnp: {
        id: 'k948zpnp',
        category: 'other',
        description: 'book',
        amount: '25',
        timeSpent: '2.5',
        time: '2020-4-21 10:48:10'
      },
      z9e8ipnp: {
        id: 'z9e8ipnp',
        category: 'food',
        description: 'pasta',
        amount: '12',
        timeSpent: '1.2',
        time: '2020-4-21 11:48:10'
      },
    },
    allIds: ['k948zpnp', 'z9e8ipnp']
  }
}

const updateTimeSpentForExpenses = (state, newInputForTimeSpent) => {
  let byId = { ...state.expenses.byId
  }
  const newObjs = Object.entries(byId).map(([key, value]) => {
    return {
      [key]: {
        ...value,
        timeSpent: value.timeSpent * newInputForTimeSpent
      }
    }
  })

  for (let newObj of newObjs) {
    Object.assign(byId, newObj)
  }

  return {
    ...state,
    expenses: {
      ...state.expenses,
      byId,
      allIds: [...state.expenses.allIds]
    }
  }
}

console.log(updateTimeSpentForExpenses(state, 10))

您可以使用for of loop代替Object.assignArray.reduce

const newObjs = Object.entries(byId).map(([key, value]) => {
      return {
       [key]: {
        ...value,
        timeSpent: value.timeSpent * newInputForTimeSpent
       }
  }
})

for(let newObj of newObjs) {
   Object.assign(byId, newObj)
}

成为

byId = Object.entries(byId).map(([key, value]) => {
      return [key, {
        ...value,
        timeSpent: value.timeSpent * newInputForTimeSpent
       }]
  }
}).reduce((acc, ([key, value]) => {
  acc[key] = value;

  return acc;
}, {})
相关问题