admin管理员组文章数量:1129779
I am using Redux. In my reducer I'm trying to remove a property from an object like this:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
And I want to have something like this without having to mutate the original state:
const newState = {
a: '1',
b: '2',
c: {
x: '42',
},
}
I tried:
let newState = Object.assign({}, state);
delete newState.c.y
but for some reasons, it deletes the property from both states.
Could help me to do that?
I am using Redux. In my reducer I'm trying to remove a property from an object like this:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
And I want to have something like this without having to mutate the original state:
const newState = {
a: '1',
b: '2',
c: {
x: '42',
},
}
I tried:
let newState = Object.assign({}, state);
delete newState.c.y
but for some reasons, it deletes the property from both states.
Could help me to do that?
Share Improve this question edited Jun 12, 2016 at 23:01 Aᴍɪʀ 7,8033 gold badges39 silver badges54 bronze badges asked Dec 21, 2015 at 17:18 Vincent TaingVincent Taing 3,3342 gold badges20 silver badges25 bronze badges 1 |17 Answers
Reset to default 321How about using destructuring assignment syntax?
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 } }
I find ES5 array methods like filter
, map
and reduce
useful because they always return new arrays or objects. In this case I'd use Object.keys
to iterate over the object, and Array#reduce
to turn it back into an object.
return Object.assign({}, state, {
c: Object.keys(state.c).reduce((result, key) => {
if (key !== 'y') {
result[key] = state.c[key];
}
return result;
}, {})
});
You can use _.omit(object, [paths])
from lodash library
path can be nested for example: _.omit(object, ['key1.key2.key3'])
Just use ES6 object destructuring feature
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
That's because you are copying the value of state.c
to the other object. And that value is a pointer to another javascript object. So, both of those pointers are pointing to the same object.
Try this:
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;
You can also do a deep-copy of the object. See this question and you'll find what's best for you.
How about this:
function removeByKey (myObj, deleteKey) {
return Object.keys(myObj)
.filter(key => key !== deleteKey)
.reduce((result, current) => {
result[current] = myObj[current];
return result;
}, {});
}
It filters the key that should be deleted then builds a new object from the remaining keys and the initial object. The idea is stolen from Tyler McGinnes awesome reactjs program.
JSBin
As of 2019, another option is to use the Object.fromEntries
method. It has reached stage 4.
const newC = Object.fromEntries(
Object.entries(state.c).filter(([key]) => key != 'y')
)
const newState = {...state, c: newC}
The nice thing about it is that it handles integer keys nicely.
function dissoc(key, obj) {
let copy = Object.assign({}, obj)
delete copy[key]
return copy
}
Also, if looking for a functional programming toolkit, look at Ramda.
You may use Immutability helper in order to unset an attribute, in your case:
import update from 'immutability-helper';
const updatedState = update(state, {
c: {
$unset: ['y']
}
});
It's easy with Immutable.js:
const newState = state.deleteIn(['c', 'y']);
description of deleteIn()
Here's an easy 1-liner you can use that allows you to partially apply the prop you want to remove. This makes it easy to pass to Array.map
.
const removeProp = prop => ({ [prop]: _, ...rest }) => ({ ...rest })
Now you can use it like this:
const newArr = oldArr.map(removeProp('deleteMe'))
The issue you are having is that you are not deep cloning your initial state. So you have a shallow copy.
You could use spread operator
const newState = { ...state, c: { ...state.c } };
delete newState.c.y
Or following your same code
let newState = Object.assign({}, state, { c: Object.assign({}, state.c) });
delete newState.c.y
I normally use
Object.assign({}, existingState, {propToRemove: undefined})
I realise this isn't actually removing the property but for almost all purposes 1 its functionally equivalent. The syntax for this is much simpler than the alternatives which I feel is a pretty good tradeoff.
1 If you are using hasOwnProperty()
, you will need to use the more complicated solution.
I use this pattern
const newState = Object.assign({}, state);
delete newState.show;
return newState;
but in book i saw another pattern
return Object.assign({}, state, { name: undefined } )
utility ;))
const removeObjectField = (obj, field) => {
// delete filter[selectName]; -> this mutates.
const { [field]: remove, ...rest } = obj;
return rest;
}
action type
const MY_Y_REMOVE = 'MY_Y_REMOVE';
action creator
const myYRemoveAction = (c, y) => {
const result = removeObjectField(c, y);
return dispatch =>
dispatch({
type: MY_Y_REMOVE,
payload: result
})
}
reducer
export default (state ={}, action) => {
switch (action.type) {
case myActions.MY_Y_REMOVE || :
return { ...state, c: action.payload };
default:
return state;
}
};
As hinted in some of the answers already, it's because you are trying to modify a nested state ie. one level deeper. A canonical solution would be to add a reducer on the x
state level:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
Deeper level reducer
let newDeepState = Object.assign({}, state.c);
delete newDeepState.y;
Original level reducer
let newState = Object.assign({}, state, {c: newDeepState});
Use a combination of Object.assign, JSON.parse and JSON.stringify
const obj1 = { a: "a", b: "b" };
const obj2 = { c: "c", a: undefined };
const merged = Object.assign({}, obj1, obj2);
const sanitized = JSON.parse(JSON.stringify(merged));
console.log(sanitized); // -> { b: "b", c: "c" }
本文标签: javascriptRemove a property in an object immutablyStack Overflow
版权声明:本文标题:javascript - Remove a property in an object immutably - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736717838a1949301.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Object.assign
creates only a shallow copy ofstate
and thereforestate.c
andnewState.c
will point to the same shared object. You tried to delete propertyy
from the shared objectc
and not from the new objectnewState
. – Akseli Palén Commented Nov 12, 2018 at 18:30