Каков самый короткий способ изменить неизменяемые объекты с помощью операторов распространения и деструктурирования?

Я ищу чистую функцию для изменения моего неизменного объекта состояния. Исходное состояние, указанное в качестве параметра, должно оставаться нетронутым. Это особенно полезно при работе с такими фреймворками, как Redux, и упрощает работу с неизменный объект в javascript намного проще. Тем более, что работа с оператором распространения объекта с помощью Babel уже возможна.

Я не нашел ничего лучше, чем сначала скопировать объект, а затем назначить/удалить свойство, которое я хочу, вот так:

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

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

Я чувствую, что это может быть короче


person Tarion    schedule 11.04.2016    source источник


Ответы (6)


Действия над состоянием, где состояние считается неизменным.

Добавление или обновление значения свойства:

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

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

Удаление ресурса

// 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);
}
person Tarion    schedule 11.04.2016
comment
Отвечая на свой вопрос через несколько секунд после вопроса?! - person ColinE; 11.04.2016
comment
Я использовал поле под формой вопроса, чтобы ответить на него, так как нашел решение до публикации вопроса. Поскольку гуглить это довольно сложно, я разместил это для всех здесь, это было. - person Tarion; 11.04.2016
comment
Но на самом деле удаление свойства тоже интересный вопрос. Поскольку установка свойства на undefined не удаляет ключ, а удаление, похоже, не работает внутри определений объектов;) - person Tarion; 11.04.2016
comment
То, что вы называете ES7, не является ES7. Распространение объекта и отдых по-прежнему является предложением. Скорее всего, это произойдет в ES2017. - person Felix Kling; 29.04.2016
comment
Хорошо, спасибо, не искал и просто последовал подсказке Ори Дрори в комментариях. Я отредактирую это. - Сделано, никаких ссылок на ES-ничего более :) - person Tarion; 03.05.2016
comment
Я хотел бы проголосовать за это больше. Я столько раз возвращался к этому посту XD - person comfortablejohn; 05.09.2017
comment
удалено не определено. что мне не хватает? - person praHoc; 18.10.2018
comment
Идея @praHoc заключалась в том, чтобы присвоить случайное значение ключу, который должен быть удален, вы могли бы указать строковое значение, удаленное, пусть {[id]: удалено, ... newState} = состояние; при этом свойство ‹id› не будет скопировано в newState - person MeanMan; 26.11.2018

Решение ES6, которое имеет немного большую поддержку, это Object.assign:

const updateState = (state, item) => Object.assign({}, state, { [item.id]: item });
person Ori Drori    schedule 11.04.2016
comment
Конечно, то же самое в стиле ES5. - person Tarion; 11.04.2016
comment
Извините, тогда нужно обновить вопрос. Используя для этого плагин babel es6 + ;) Немного запутался. - person Tarion; 11.04.2016
comment
На самом деле стрелочные функции доступны только в ES6, поэтому этот фрагмент — ES6. - person Luca Fagioli; 27.06.2017

В функции карты

Чтобы выполнить этот процесс в функции карты (удалить атрибут и добавить новый атрибут для каждого объекта), учитывая массив объектов -

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

Удалите атрибут keyToDelete и добавьте новый ключ newKey со значением "someVar".

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

Обновление массива до

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

Дополнительную информацию о метод удаления.

person Aidan Ewen    schedule 25.07.2018

Вместо написания стандартного кода (как указано выше: (({[id]: deleted, ...state}) => state)(state)), который трудно читать, вы можете использовать некоторую библиотеку, чтобы сделать то же самое:

Например:

import {remove} from 'immutable-modify'

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

Он также поддерживает любые вложенные обновления:

import {set} from 'immutable-modify'

function updateState(state, item) {
   return set(state, 'user.products', (products) => ({
      ...products,
      items: products.items.concat(item),
      lastUpdate: Date.now()
   }))
}
person Oleksandr Kozlov    schedule 19.07.2018

Пытаться:

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

И тест:

console.log(noId);
person ali    schedule 05.03.2019

Удаление элемента из массива, просто используйте фильтр;)

CASE 'REMOVE_ITEM_SUCCESS':

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

      return {
            ...state, 
            items
      }
person webmaster    schedule 01.02.2018