如何使用 JavaScript spread... 语法更改属于数组并通过名称-值对访问的对象的一个​​字段?

How to use JavaScript spread... syntax to change the one field of the object, that belongs to the array and is accessed by name-value pair?

代码如下(在构建state2的语句处编译失败,即在第二次传播时):

let line_id = 6;

let state = {
  invoice: {
    id: 1015,
    description: 'web order',
  },
  lines: [
    {id: 5, description: 'phone', color: 'black'},
    {id: 6, description: 'tablet', color: 'blue'},
    {id: 7, description: 'computer', color: 'gray'},
  ]
};

//this alert and this access pattern works, so, I would like to use
//.find... to access element in spread... structure as well
//alert(state['lines'].find(line=>line['id']==line_id)['description']);

let state2 = {
   ...state,
   ['lines']: { ...state['lines'],
      find(line=>line['id']==line_id): { ...state['lines'].find(line=>line['id']==line_id),
      ['description']: 'TV',
      },
   },
};

alert(state2['lines'].find(line=>line['id']==line_id)['description']);

我有 state 结构,我访问 lines 数组,我通过名称-值对访问特定行 id=6 我想更改字段的值 description。这项工作是 的延续,我在其中尝试创建通用过程,该过程使用 spread... 语法和按名称访问策略来更新复杂的 object/array 树。事实上 - 这个复杂的树是 Redux reducer 的状态,并且更新发生在处理 AgGrid 的 valueSetter 函数的操作中。但是 - 这本身就是一个有趣的练习,可以更好地理解传播...以及 JavaScript 和 JSON 中的结构 JavaScript.

所以 - 唯一的问题是:如何写行

find(line=>line['id']==line_id): { ...state['lines'].find(line=>line['id']==line_id),

以便代码编译?如何在此设置中通过名称-值对访问数组的特定元素:

请注意,我正在尝试构建通用代码:

find(line=>line[keyFieldName]==keyFieldValue): { ...state['lines'].find(line=>line[keyFieldName]==keyFieldValue),

使用任意字段名称和字段值 - 这样的处理程序可以在 React/Redux 设置中更新任意 2D AgGrid 的任意记录的任意字段。

我的代码的预期结果:1) 它应该编译; 2) 第二个警报应该 return 'TV'.

如果我正确理解了你想要实现的目标,这应该可行:

let line_id = 6;

let state = {
  invoice: {
    id: 1015,
    description: 'web order',
  },
  lines: [{
      id: 5,
      description: 'phone',
      color: 'black'
    },
    {
      id: 6,
      description: 'tablet',
      color: 'blue'
    },
    {
      id: 7,
      description: 'computer',
      color: 'gray'
    },
  ]
};

const stateKeyId = 'lines';
const itemKeyId = 'id';
const itemAttr = 'description'

let state2 = {
  ...state,
  [stateKeyId]: state[stateKeyId].map(item => {
    if (item[itemKeyId] == line_id) {
      return ({
        ...item,
        [itemAttr]: 'TV'
      });
    }
    return item
  })
}

console.log(state2);

find(line=>line['id']==line_id) 应该变成 [find(line=>line['id']==line_id)],因为就像字符串一样,它必须在方括号之间才能使 js 正常工作。

此外,如果您使用 lodash 中的 find,它将 return 对象,因此如果您需要使用 id 作为键,您可以执行以下操作:

[get(find(line => line['id'] === line_id]), 'id')]: whatever

一些观察结果:

  • 总是请总是在 js 中使用 === 而不是 ==
  • 避免snake_case,在 js 中使用驼峰式大小写,因为它是标准的
  • 您的代码实际上并没有正确处理丢失的项目,如果您需要这样做,请将其分成多行,因为这样会更容易理解

您可以使用 map 方法从数组到 return 个基于原始元素的不同元素。

以下是您的使用方法:

line_id = 6;

state = {
  invoice: {
    id: 1015,
    description: 'web order',
  },
  lines: [
    {id: 5, description: 'phone', color: 'black'},
    {id: 6, description: 'tablet', color: 'blue'},
    {id: 7, description: 'computer', color: 'gray'},
  ]
};

state2 = {
   ...state,
   lines: state.lines.map(line => {
     if (line.id === line_id)
       return { ...line, description: 'YT' }
     return { ...line }
   })
};

alert(state2['lines'].find(line=>line['id']==line_id)['description']);