Skip to content Skip to sidebar Skip to footer

How To Spread Nested Properties In Object?

I have this object below. I was wondering how I can select a specific item and update a property. For example. Item 1 I want to add a task in the array. item: { 'item-1': { i

Solution 1:

You need to use the object key i.e item-1 and clone the properties for it and add the new list for the task key. In short you need to clone at each level of the object before overriding the key that you wish to update

const newState = {
  ...state,
  items: {
    ...state.items,
    'item-1': {
         ...state.items['item-1'],
         task: newTaskList
     }
  }
};

Solution 2:

Assuming the starting point:

let state = {
    items: {
      'item-1': {
        id: 'item-1',
        title: 'To do',
        task: ['task-1', 'task-2', 'task-3', 'task-4']
      },
      'item-2': {
        id: 'item-2',
        title: 'In progress',
        task: []
      },
    }
};

If you want to add a task to item-1's task array without modifying things in place (which is important in React state), you have to copy state, items, item-1, and item-1's task:

let newState = {
    ...state,
    items: {
        ...state.items,
        'item-1': {
            ...state.items['item-1'],
            task: [...state.items['item-1'].task, newTask]
        }
    }
};

Live Example:

let state = {
    items: {
      'item-1': {
        id: 'item-1',
        title: 'To do',
        task: ['task-1', 'task-2', 'task-3', 'task-4']
      },
      'item-2': {
        id: 'item-2',
        title: 'In progress',
        task: []
      },
    }
};

let newTask = "task-4";

let newState = {
    ...state,
    items: {
        ...state.items,
        'item-1': {
            ...state.items['item-1'],
            task: [...state.items['item-1'].task, newTask]
        }
    }
};

console.log(newState);

Solution 3:

In lodadash you can get and set nested object from an object, here is my own implementation of it:

//helper to get prop from objectconstget = (object, path, defaultValue) => {
  constrecur = (object, path) => {
    if (object === undefined) {
      return defaultValue;
    }
    if (path.length === 0) {
      return object;
    }
    returnrecur(object[path[0]], path.slice(1));
  };
  returnrecur(object, path);
};
//helper to set nested prop in objectconstset = (
  state,
  statePath,
  modifier
) => {
  constrecur = (result, path) => {
    const key = path[0];
    if (path.length === 0) {
      returnmodifier(get(state, statePath));
    }
    returnArray.isArray(result)
      ? result.map((item, index) =>
          index === Number(key)
            ? recur(item, path.slice(1))
            : item
        )
      : {
          ...result,
          [key]: recur(result[key], path.slice(1)),
        };
  };
  const newState = recur(state, statePath);
  returnget(state, statePath) === get(newState, statePath)
    ? state
    : newState;
};

let state = {
  items: {
    'item-1': {
      id: 'item-1',
      title: 'To do',
      task: ['task-1', 'task-2', 'task-3', 'task-4'],
    },
    'item-2': {
      id: 'item-2',
      title: 'In progress',
      task: [],
    },
  },
};
console.log(
  set(
    state,
    ['items','item-1','task'],
    (tasks)=>tasks.concat('new task')
  )
);

You can put the get and set in a library and it would make setting deeply nested values easier on the eyes of future readers of your code.

Post a Comment for "How To Spread Nested Properties In Object?"