web-dev-qa-db-ja.com

オブジェクトのプロパティを不変に削除します

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

しかし、何らかの理由で、両方の状態からプロパティを削除します。

それを手伝ってくれる?

107
Vincent Taing

destructuring assignment 構文を使用してはどうですか?

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

filtermapreduceなどのES5配列メソッドは、常に新しい配列またはオブジェクトを返すため便利です。この場合、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;
    }, {})
});
45
David L. Walsh

lodash libraryから_.omit(object, [paths])を使用できます

パスは、たとえば次のようにネストできます:_.omit(object, ['key1.key2.key3'])

34
Dmitri

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
23
Ramon Diogo

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;

オブジェクトの詳細コピーを行うこともできます。 この質問 を参照すると、最適なものが見つかります。

22
Aᴍɪʀ

これはどう:

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

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

また、関数型プログラミングツールキットを探している場合は、 Ramda を見てください。

10

あなたの場合、属性を設定解除するために Immutability helper を使用できます:

import update from 'immutability-helper';

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

Immutable.js で簡単です:

const newState = state.deleteIn(['c', 'y']);

deleteIn()の説明

5
quotesBro

あなたが抱えている問題は、初期状態を深く複製していないことです。浅いコピーがあります。

スプレッド演算子を使用できます

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

または同じコードに従う

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

私は通常使用します

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

これは実際にプロパティを削除するのではなく、ほとんどすべての目的のために 1 機能的に同等です。この構文は、かなり良いトレードオフだと思う代替案よりもはるかに単純です。

1 hasOwnProperty()を使用している場合、より複雑なソリューションを使用する必要があります。

1
Luke McGregor

私はこのパターンを使用します

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

しかし、本で私は別のパターンを見ました

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

2019年現在、別のオプションはObject.fromEntriesメソッドを使用することです。ステージ4に到達しました。

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

それの良いところは、整数キーをうまく処理できることです。

0
yidaohuuu

ユーティリティ;))

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
Musa

すでにいくつかの答えで示唆されているように、それは、ネストされた状態を変更しようとしているためです。 1レベル深い。正規の解決策は、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});
0
Mieszko