Подтвердить что ты не робот

Удалить свойство в объекте неизменно

Я использую Redux. В моем редукторе я пытаюсь удалить свойство из объекта следующим образом:

const state = {
    a: '1',
    b: '2',
    c: {
       x: '42',
       y: '43'
    },
}

И я хочу иметь что-то вроде этого без необходимости изменять исходное состояние:

const newState = {
    a: '1',
    b: '2',
    c: {
       x: '42',
    },
}

Я пробовал:

let newState = Object.assign({}, state);
delete newState.c.y

но по некоторым причинам он удаляет свойство из обоих состояний.

Помогло бы мне это сделать?

4b9b3361

Ответ 1

Как насчет использования синтаксиса деструктурирования?

const original = {
  foo: 'bar',
  stack: 'overflow',
};

// If the name of the property to remove is constant
const { stack, ...withoutFirst } = original;
console.log(withoutFirst); // Will be { "foo": "bar" }

// If the name of the property to remove is from a variable
const key = 'stack'
const { [key]: value, ...withoutSecond } = original;
console.log(withoutSecond); // Will be { "foo": "bar" }

// To do a deep removal with property names from variables
const deep = {
  foo: 'bar',
  c: {
   x: 1,
   y: 2
  }
};

const parentKey = 'c';
const childKey = 'y';
// Remove the 'c' element from original
const { [parentKey]: parentValue, ...noChild } = deep;
// Remove the 'y' from the 'c' element
const { [childKey]: removedValue, ...childWithout } = parentValue;
// Merge back together
const withoutThird = { ...noChild, [parentKey]: childWithout };
console.log(withoutThird); // Will be { "foo": "bar", "c": { "x": 1 } }

Ответ 2

Я нахожу методы массива ES5, такие как filter, map и reduce полезными, потому что они всегда возвращают новые массивы или объекты. В этом случае я использовал бы Object.keys для итерации по объекту и Array#reduce, чтобы вернуть его обратно в объект.

return Object.assign({}, state, {
    c: Object.keys(state.c).reduce((result, key) => {
        if (key !== 'y') {
            result[key] = state.c[key];
        }
        return result;
    }, {})
});

Ответ 3

Вы можете использовать _.omit(object, [paths]) из библиотеки lodash

путь может быть вложенным, например: _.omit(object, ['key1.key2.key3'])

Ответ 4

Это потому, что вы копируете значение state.c на другой объект. И это значение является указателем на другой объект javascript. Таким образом, оба указателя указывают на один и тот же объект.

Попробуйте следующее:

let newState = Object.assign({}, state);
console.log(newState == state); // false
console.log(newState.c == state.c); // true
newState.c = Object.assign({}, state.c);
console.log(newState.c == state.c); // now it is false
delete newState.c.y;

Вы также можете сделать глубокую копию объекта. См. этот вопрос, и вы найдете то, что лучше для вас.

Ответ 5

Просто используйте функцию разрушения объектов ES6

const state = {
    c: {
       x: '42',
       y: '43'
    },
}

const { c: { y, ...c } } = state // generates a new 'c' without 'y'

console.log({...state, c }) // put the new c on a new state

Ответ 6

Как насчет этого:

function removeByKey (myObj, deleteKey) {
  return Object.keys(myObj)
    .filter(key => key !== deleteKey)
    .reduce((result, current) => {
      result[current] = myObj[current];
      return result;
  }, {});
}

Он фильтрует ключ, который следует удалить, а затем создает новый объект из остальных ключей и исходного объекта. Идея украдена из программы Tyler McGinnes awesome reactjs.

JSBin

Ответ 7

function dissoc(key, obj) {
  let copy = Object.assign({}, obj)
  delete copy[key]
  return copy
}

Кроме того, если вы ищете функциональный инструментарий программирования, посмотрите на Ramda.

Ответ 8

Вы можете использовать Immutability helper для удаления атрибута, в вашем случае:

import update from 'immutability-helper';

const updatedState = update(state, {
  c: {
    $unset: ['y']
  }
});    

Ответ 10

Проблема, с которой вы столкнулись, заключается в том, что вы не глубоко копируете свое первоначальное состояние. Итак, у вас есть мелкая копия.

Вы можете использовать спред оператора

  const newState = { ...state, c: { ...state.c } };
  delete newState.c.y

Или следуя тому же коду

let newState = Object.assign({}, state, { c: Object.assign({}, state.c) });
delete newState.c.y

Ответ 11

Обычно я использую

Object.assign({}, existingState, {propToRemove: undefined})

Я понимаю, что это фактически не снимает свойство, но почти для всех целей 1 его функционально эквивалентно. Синтаксис для этого намного проще, чем альтернативы, которые, как я считаю, являются довольно хорошим компромиссом.

1 Если вы используете hasOwnProperty(), вам нужно будет использовать более сложное решение.

Ответ 12

Я использую этот шаблон

const newState = Object.assign({}, state);
      delete newState.show;
      return newState;

но в книге я увидел другой образец

return Object.assign({}, state, { name: undefined } )

Ответ 13

Как уже намечено в некоторых ответах, это потому, что вы пытаетесь изменить вложенное состояние, т.е. на один уровень глубже. Каноническим решением было бы добавить редуктор на уровне состояния x:

const state = {
    a: '1',
    b: '2',
    c: {
       x: '42',
       y: '43'
    },
}

Более глубокий редуктор уровня

let newDeepState = Object.assign({}, state.c);
delete newDeepState.y;

Редуктор исходного уровня

let newState = Object.assign({}, state, {c: newDeepState});

Ответ 14

полезность ;))

const removeObjectField = (obj, field) => {

    // delete filter[selectName]; -> this mutates.
    const { [field]: remove, ...rest } = obj;

    return rest;
}

тип действия

const MY_Y_REMOVE = 'MY_Y_REMOVE';

создатель действия

const myYRemoveAction = (c, y) => {

    const result = removeObjectField(c, y);

        return dispatch =>
            dispatch({
                type: MY_Y_REMOVE,
                payload: result
            })
    }

редуктор

export default (state ={}, action) => {
  switch (action.type) {
    case myActions.MY_Y_REMOVE || :
      return { ...state, c: action.payload };
    default:
      return state;
  }
};

Ответ 15

Начиная с 2019 года, другим вариантом является использование метода Object.fromEntries. Он достиг стадии 4.

const newC = Object.fromEntries(
    Object.entries(state.c).filter(([key]) => key != 'y')
)
const newState = {...state, c: newC}

Приятно то, что он прекрасно обрабатывает целочисленные ключи.

Ответ 16

Вы можете использовать React immutability helpers, чтобы перезаписать либо весь c, если у вас есть это, либо для установки значения y до undefined или null. Это зависит от вашего варианта использования, который может работать лучше всего:

const newState = update(state, {
  c: {$set: {
    x: '42',
  }},
});

или

const newState2 = update(state, {
  c: {
    y: {$set: undefined},
  },
});