Search code examples
javascriptjsonobjectkeyinsertion-order

Changing Object keys & values and preserving the initial order


Given the state object below

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

I need to be able to change/update its attribute values attrValues as well as the attribute keys attrKey

I'm using the following logic to do so:

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

If I change the attribute key for colour to color it works but the resulting state change to:

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

Moving the color attribute to the end, I would like to keep it in its original position.

Any help or pointers will be much appreciated.


Solution

  • Though one should take into account the expressed concerns about key insertion order / precedence the solution the OP is looking for might come close to something like the next provided code ...

    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; }