불변으로 객체의 속성 제거


145

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

그러나 어떤 이유로 든 두 상태에서 속성을 삭제합니다.

내가 도와 줄 수 있습니까?


3
참고 Object.assign만 생성 얕은 복사 의를 state따라서 state.cnewState.c동일한 공유 객체를 가리 킵니다. 새 객체가 아닌 y공유 객체에서 속성을 삭제하려고했습니다 . cnewState
Akseli Palén

답변:


224

파괴 할당 구문을 사용하는 것은 어떻 습니까?

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


3
추가 라이브러리없이 훌륭하게 es6을 사용하고 충분히 간단하게 만듭니다.
sbk201

가장 우아한 솔루션
long.luc

12
좋은! 다음은 es6 도우미 기능 const deleteProperty = ({[key]: _, ...newObj}, key) => newObj;입니다. 사용법 : deleteProperty({a:1, b:2}, "a");제공{b:2}
mikebridge

슈퍼 영리한, 나는 이것에 늦었지만 나의 새로운 마음에 드는 것 중 하나
Gavin

1
deep['c']비어있는 경우 깊은 제거 예제가 중단 되므로 일반적인 경우 키가 있는지 확인하는 것이 좋습니다.
Laurent S

46

내가 좋아하는 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;
    }, {})
});

좀 더 명확한 IMO를 만들기 위해 약간의 변화를 겪었습니다. 또한 여러 속성을 생략 할 수 있습니다. const omit = [ 'prop1', 'prop2'] ... if (omit.indexOf (key) === -1) result [key] = state.c [key] 반환 결과; ...
josh-sachs

3
myObject키가 myKey제거 된 사본을 얻는 것과 동등한 ES6 :Object.keys(myObject).reduce((acc, cur) => cur === myKey ? acc : {...acc, [cur]: myObject[cur]}, {})
transang

38

lodash 라이브러리 _.omit(object, [paths])에서 사용할 수 있습니다

경로는 다음과 같이 중첩 될 수 있습니다. _.omit(object, ['key1.key2.key3'])


3
불행히도, _.omit심층 속성 (OP가 요청한 것)은 삭제할 수 없습니다. 있다 omit-deep-lodash이러한 목적을 위해 모듈.
AlexM

2
@AlexM이 말한 것을 제거합니다. 나는 그것이 _.cloneDeep(obj)lodash 에서 우리에게 유용하고 더 적절하다고 생각했습니다. 객체를 쉽게 복사 한 다음 js delete obj.[key]를 사용 하여 키를 제거 할 수 있습니다 .
Alex J

@AlexJ와 동의하면 cloneDeep은 완벽하게 작동하며 스프레드 구문도 사용할 수 있습니다. ..._. cloneDeep (state) for Redux
Sean Chase

32

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


8
const {y, ...c} = state.cc왼쪽에 2가있는 것보다 조금 더 명확 할 수 있습니다 .
dosentmatter

10
주의 : 정수로 입력 된 객체에는 작동하지 않습니다.
daviestar

3
아래 답변에서 삭제할 변수 이름을 참조 해야하는 경우 감속기에서 반환 const name = 'c'할 수 있습니다 . 이것은 최상위 키 삭제를위한 것입니다.const {[name]:deletedValue, ...newState} = statenewState
FFF

23

state.c다른 객체에 값을 복사하기 때문 입니다. 그리고 그 가치는 다른 자바 스크립트 객체에 대한 포인터입니다. 따라서 두 포인터 모두 동일한 객체를 가리 킵니다.

이 시도:

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;

객체의 정밀 복사를 수행 할 수도 있습니다. 참조 이 질문에 당신은 당신을 위해 최선의 기능을 얻을 수 있습니다.


2
이것은 훌륭한 답변입니다! state.c참조이며 참조가 잘 복사됩니다. Redux는 표준화 된 상태 형태를 원합니다. 이는 상태를 중첩 할 때 참조 대신 ID를 사용하는 것을 의미합니다. redux 문서를 확인하십시오 : redux.js.org/docs/recipes/reducers/NormalizingStateShape.html
Ziggy

17

이건 어때요:

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

삭제해야 할 키를 필터링 한 다음 나머지 키와 초기 객체에서 새 객체를 만듭니다. 아이디어는 Tyler McGinnes의 멋진 reactjs 프로그램에서 도난당했습니다.

JSBin



9

다음과 같은 경우, 속성을 설정 해제하기 위해 불변성 헬퍼 를 사용할 수 있습니다 .

import update from 'immutability-helper';

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

그런 다음 모든 배열 객체 항목의 모든 속성 "y"를 삭제하는 방법은 무엇입니까?
5ervant

@ 5ervant 나는 이것이 또 다른 질문이라고 생각하지만 배열을 매핑하고 여기에 주어진 솔루션을 적용하는 것이 좋습니다.
Javier P

8

2019 년 현재 다른 방법은이 Object.fromEntries방법 을 사용하는 것입니다. 4 단계에 도달했습니다.

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

그것에 대한 좋은 점은 정수 키를 잘 처리한다는 것입니다.



3

당신이 겪고있는 문제는 초기 상태를 깊게 복제하지 않는다는 것입니다. 얕은 사본이 있습니다.

스프레드 연산자를 사용할 수 있습니다

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

또는 동일한 코드를 따르십시오.

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

1

나는 보통

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

나는 이것이 실제로 속성을 제거하지만, 거의 모든 목적으로하지 않습니다 실현 그 기능적으로 동일. 이것에 대한 구문은 내가 생각하는 대안보다 훨씬 간단합니다.

1 당신이 사용하는 경우 hasOwnProperty(), 당신은 더 복잡한 솔루션을 사용해야합니다.


1

이 패턴을 사용합니다

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

그러나 책에서 나는 또 다른 패턴을 보았다

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

두 번째는 키를 제거하지 않습니다. 정의되지 않은 것으로 설정합니다.
bman

1

유틸리티;))

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

0

이미 일부 답변에서 암시 한 것처럼 중첩 상태를 수정하려고하기 때문입니다. 한 단계 더 깊이. 표준 솔루션은 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});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.