不可移动地移除对象中的属性
我正在使用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
但由于某些原因,它从两种状态中删除属性。
能帮我做到吗?
只需使用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
这是因为您正在将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;
你也可以做对象的深副本。见this question,你会发现什么是最适合你的。
我发现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] return result; ... –
ES6相当于使用键“myKey”获得'myObject'副本:'Object.keys(myObject).reduce((acc,cur)=> cur === myKey?acc:{... acc,[ cur]:myObject [cur]},{})' – transang
如何:
function removeByKey (myObj, deleteKey) {
return Object.keys(myObj)
.filter(key => key !== deleteKey)
.reduce((result, current) => {
result[current] = myObj[current];
return result;
}, {});
}
它过滤应然后删除密钥从剩余的键和初始对象中构建一个新对象。这个想法从Tyler McGinnes真棒reactjs程序中被盗。
function dissoc(key, obj) {
let copy = Object.assign({}, obj)
delete copy[key]
return copy
}
而且,如果寻找一个函数式编程工具包,看看Ramda。
您可以使用Immutability helper以取消设置的属性,你的情况:
import update from 'immutability-helper';
const updatedState = update(state, {
c: {
$unset: ['y']
}
});
如何使用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 } }
美妙,没有额外的库,使用es6和足够简单。 – sbk201
最优雅的解决方案 –
不错!这里有一个es6帮助函数,它和它一起'const deleteProperty =({[key]:_,... newObj},key)=> newObj;'。用法:'deleteProperty({a:1,b:2},“a”);'给出'{b:2}' – mikebridge
我通常使用
Object.assign({}, existingState, {propToRemove: undefined})
我知道这是不是真正删除的财产,但几乎所有的目的其功能上等同。这个语法比我认为是一个很好的折衷方案更简单。
如果您使用的是hasOwnProperty()
,则需要使用更复杂的解决方案。
正如已经暗示的一些答案,这是因为你试图修改一个嵌套的状态,即。更深一层。一个典型的解决方案将是在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});
我使用这个模式
const newState = Object.assign({}, state);
delete newState.show;
return newState;
但是在本书中,我看到了另一种模式
return Object.assign({}, state, { name: undefined })
效用;))
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;
}
};
这是一个很好的答案! 'state.c'是一个引用,并且引用被复制得很好。 Redux想要一个规范化的状态形状,这意味着在嵌套状态时使用id而不是引用。看看REDX文档:http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html – Ziggy