更改对象键和值并保留初始顺序

Changing Object keys & values and preserving the initial order

给出下面的状态对象

{
  colour: ['red', 'blue', 'green'],
  size: ['small', 'medium', 'large'],
  position: ['bottom', 'top', 'left', 'right'],
}

我需要能够change/update它的属性值attrValues以及属性键attrKey

我正在使用以下逻辑来执行此操作:

setAttributes((prevState) => {
  const key = Object.keys(attributeToUpdate)[0];
  if (key !== attrKey) {
    delete prevState[key];
  }
  return { ...prevState, [attrKey]: attrValue };
});

如果我将 colour 的属性键更改为 color 它有效,但结果状态更改为:

{
  size: ['small', 'medium', 'large'],
  position: ['bottom', 'top', 'left', 'right'],
  color: ['red', 'blue', 'green'],
}

color属性移到末尾,我想保留在原来的位置。

任何帮助或指点将不胜感激。

您无法控制 n 对象中键的顺序 - 如果顺序很重要,您应该有一个对象数组。然后你可以重建删除你想要的项目并替换它的状态。

下面的演示在实践中展示了这一点:

let prevState = [
  {key:"colour",values: ['red', 'blue', 'green']},
  {key:"size", values:['small', 'medium', 'large']},
  {key:"position",values:['bottom', 'top', 'left', 'right']}
]

const indexToRemove = prevState.findIndex(x => x.key == "colour");

prevState = [
  ...prevState.slice(0,indexToRemove),
  {key:"color", values:['red', 'blue', 'green']},
  ...prevState.slice(indexToRemove+1)
]
console.log(prevState)

所以如果我理解你的代码,更正将是

setAttributes((prevState) => {
  const key = Object.keys(attributeToUpdate)[0];
  const indexToRemove = prevState.findIndex(x => x.key == key);

  return [
    ...prevState.slice(0,indexToRemove),
    {key:attrKey, values:attrValue},
    ...prevState.slice(indexToRemove+1)
  ]
});

而且您必须更新其余代码才能使用状态数组而不是对象。

虽然应该考虑到对密钥插入顺序/优先级的担忧,但 OP 正在寻找的解决方案可能接近于下一个提供的代码...

function renamePropertyAndKeepKeyPrecedence(obj, [oldKey, newKey]) {
  const descriptors = Object.getOwnPropertyDescriptors(obj);
  if (descriptors.hasOwnProperty(oldKey)) {
    Object
      .entries(descriptors)
      .reduce((target, [key, descriptor]) => {

        // delete every property.
        Reflect.deleteProperty(target, key);

        if (key === oldKey) {
          // rename addressed key.
          key = newKey;
        }
        // reassign every property.
        Reflect.defineProperty(target, key, descriptor)

        return target;

      }, obj);
  }
  return obj;
}

const sample = {
  position: ['bottom', 'top', 'left', 'right'],
  colour: ['red', 'blue', 'green'],
  size: ['small', 'medium', 'large'],
};
console.log('before property renaming ...', { sample });

renamePropertyAndKeepKeyPrecedence(sample, ['colour', 'color']);
console.log('after property renaming ...', { sample });
.as-console-wrapper { min-height: 100%!important; top: 0; }