What is the shortest way to modify immutable objects using spread and destructuring operators

I'm looking for a pure function, to modify my immutable state object. The original state given as parameter must stay untouched. This is especially useful when working with frameworks like Redux and makes working with immutable object in javascript much easier. Especially since working with the object spread operator using Babel is already possible.

I did not found anything better than first copy the object, and than assign/delete the property I want like this:

function updateState(state, item) {
  newState = {...state};
  newState[item.id] = item;
  return newState;
}

function deleteProperty(state, id) {
    var newState = {...state};
    delete newState[id];
    return newState;
}

I feel like it could be shorter

Answers:

Answer

Actions on state, where state is considered immutable.

Adding or Updating the value of a property:

// ES6:
function updateState(state, item) {
    return Object.assign({}, state, {[item.id]: item});
}

// With Object Spread:
function updateState(state, item) {
  return {
     ...state,
     [item.id]: item
  };
}

Deleting a property

// ES6:
function deleteProperty(state, id) {
    var newState = Object.assign({}, state);
    delete newState[id];
    return newState; 
}

// With Object Spread:
function deleteProperty(state, id) {
    let  {[id]: deleted, ...newState} = state;
    return newState;
}

// Or even shorter as helper function:
function deleteProperty({[id]: deleted, ...newState}, id) {
    return newState;
}

// Or inline:
function deleteProperty(state, id) {
    return (({[id]: deleted, ...newState}) => newState)(state);
}
Answer

An ES6 solution, that has a bit more support is Object.assign:

const updateState = (state, item) => Object.assign({}, state, { [item.id]: item });
Answer

In a Map Function

To do this process within a map function (remove an attribute and add a new attribute on each object), given an array of objects -

const myArrayOfObjects = [
    {id: 1, keyToDelete: 'nonsense'},
    {id: 2, keyToDelete: 'rubbish'}
];

Delete the attribute keyToDelete, and add a new key newKey with the value "someVar".

myArrayOfObjects.map(({ keyToDelete, ...item}) => { ...item, newKey:'someVar'});

Updating the array to

[
    {id: 1, newKey:'someVar'},
    {id: 2, newKey:'someVar'}
]

See this great post for more information on the deletion method.

Answer

Instead of writing boilerplate code (as answered above: (({[id]: deleted, ...state}) => state)(state)) which is hard to read, you could use some library to do the same:

For example:

import {remove} from 'immutable-modify'

function updateState(state, item) {
   return remove(state, item.id)
}

It's also supports any nested updates:

import {set} from 'immutable-modify'

function updateState(state, item) {
   return set(state, 'user.products', (products) => ({
      ...products,
      items: products.items.concat(item),
      lastUpdate: Date.now()
   }))
}
Answer

Try:

const { id, ...noId } = state;

And test:

console.log(noId);
Answer

Removing item from an array, just use filter ;)

CASE 'REMOVE_ITEM_SUCCESS':

      let items = state.items.filter(element => element._id !== action.id);

      return {
            ...state, 
            items
      }

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.