J'utilise Redux. Dans mon réducteur, j'essaie de supprimer une propriété d'un objet comme celui-ci:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
Et je veux avoir quelque chose comme ça sans avoir à muter l’état original:
const newState = {
a: '1',
b: '2',
c: {
x: '42',
},
}
J'ai essayé:
let newState = Object.assign({}, state);
delete newState.c.y
mais pour certaines raisons, il supprime la propriété des deux états.
Pourrait m'aider à faire ça?
Que diriez-vous d'utiliser la syntaxe attribution de déstructuration ?
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 } }
Les méthodes de tableaux ES5 telles que filter
, map
et reduce
sont utiles car elles renvoient toujours de nouveaux tableaux ou objets. Dans ce cas, j'utiliserais Object.keys
pour parcourir l'objet, et Array#reduce
pour le reconvertir en objet.
return Object.assign({}, state, {
c: Object.keys(state.c).reduce((result, key) => {
if (key !== 'y') {
result[key] = state.c[key];
}
return result;
}, {})
});
Vous pouvez utiliser _.omit(object, [paths])
de lodash library
chemin peut être imbriqué par exemple: _.omit(object, ['key1.key2.key3'])
Il suffit d'utiliser la fonctionnalité de déstructuration d'objet 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
C'est parce que vous copiez la valeur de state.c
vers l'autre objet. Et cette valeur est un pointeur sur un autre objet javascript. Ainsi, ces deux pointeurs pointent sur le même objet.
Essaye ça:
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;
Vous pouvez également faire une copie en profondeur de l'objet. Voir cette question et vous trouverez ce qui vous convient le mieux.
Que dis-tu de ça:
function removeByKey (myObj, deleteKey) {
return Object.keys(myObj)
.filter(key => key !== deleteKey)
.reduce((result, current) => {
result[current] = myObj[current];
return result;
}, {});
}
Il filtre la clé à supprimer, puis crée un nouvel objet à partir des clés restantes et de l’objet initial. L'idée est volée au programme impressionnant de Tyler McGinnes.
function dissoc(key, obj) {
let copy = Object.assign({}, obj)
delete copy[key]
return copy
}
En outre, si vous recherchez une boîte à outils de programmation fonctionnelle, regardez Ramda .
Vous pouvez utiliser assistant d'immutabilité pour supprimer un attribut, dans votre cas:
import update from 'immutability-helper';
const updatedState = update(state, {
c: {
$unset: ['y']
}
});
C'est facile avec Immutable.js :
const newState = state.deleteIn(['c', 'y']);
Le problème que vous rencontrez est que vous n'êtes pas en train de cloner en profondeur votre état initial. Donc, vous avez une copie superficielle.
Vous pouvez utiliser l'opérateur spread
const newState = { ...state, c: { ...state.c } };
delete newState.c.y
Ou en suivant votre même code
let newState = Object.assign({}, state, { c: Object.assign({}, state.c) });
delete newState.c.y
J'utilise normalement
Object.assign({}, existingState, {propToRemove: undefined})
Je me rends compte que ce n'est pas réellement enlever la propriété, mais pour presque toutes les fins 1 son équivalent fonctionnel. La syntaxe utilisée est bien plus simple que les alternatives, ce qui, à mon avis, est un très bon compromis.
1 Si vous utilisez hasOwnProperty()
, vous devrez utiliser la solution plus complexe.
À partir de 2019, une autre option consiste à utiliser la méthode Object.fromEntries
. Il a atteint l'étape 4.
const newC = Object.fromEntries(
Object.entries(state.c).filter(([key]) => key != 'y')
)
const newState = {...state, c: newC}
La bonne chose à ce sujet est qu’elle gère bien les clés entières.
J'utilise ce motif
const newState = Object.assign({}, state);
delete newState.show;
return newState;
mais dans le livre j'ai vu un autre motif
return Object.assign({}, state, { name: undefined } )
tilité;))
const removeObjectField = (obj, field) => {
// delete filter[selectName]; -> this mutates.
const { [field]: remove, ...rest } = obj;
return rest;
}
type d'action
const MY_Y_REMOVE = 'MY_Y_REMOVE';
créateur d'action
const myYRemoveAction = (c, y) => {
const result = removeObjectField(c, y);
return dispatch =>
dispatch({
type: MY_Y_REMOVE,
payload: result
})
}
réducteur
export default (state ={}, action) => {
switch (action.type) {
case myActions.MY_Y_REMOVE || :
return { ...state, c: action.payload };
default:
return state;
}
};
Comme cela a déjà été suggéré dans certaines des réponses, c'est parce que vous essayez de modifier un état imbriqué, par exemple. un niveau plus profond. Une solution canonique serait d’ajouter un réducteur au niveau de l’état x
:
const state = {
a: '1',
b: '2',
c: {
x: '42',
y: '43'
},
}
Réducteur de niveau plus profond
let newDeepState = Object.assign({}, state.c);
delete newDeepState.y;
Réducteur de niveau d'origine
let newState = Object.assign({}, state, {c: newDeepState});