J'ai une question concernant la prévention de l'ajout de doublons dans mon magasin Redux.
Cela devrait être simple, mais pour une raison quelconque, rien ne fonctionne.
export const eventReducer = (state = [], action) => {
switch(action.type) {
case "ADD_EVENT":
return [...state, action.event].filter(ev => {
if(ev.event_id !== action.event.event_id){
return ev;
}
});
default:
return state;
}
};
La action
ressemble à quelque chose comme ci-dessous:
{
type: "ADD_EVENT",
event: { event_id: 1, name: "Chelsea v Arsenal" }
}
Le problème est que, parfois, l'API avec laquelle je travaille envoie des messages identiques via un WebSocket, ce qui signifie que deux événements identiques sont ajoutés à mon magasin.
J'ai adopté de nombreuses approches, mais je n'arrive pas à comprendre comment le faire fonctionner. J'ai essayé beaucoup de réponses SO,
Pourquoi votre code échoue?
Code:
return [...state, action.event].filter(ev => {
if(ev.event_id !== action.event.event_id){
return ev;
}
});
Parce que vous ajoutez d’abord le nouvel élément, puis que vous filtrez le même élément , il n’ajoutera jamais la nouvelle valeur à l’état de réduction.
Solution:
Utilisez # array.findIndex pour vérifier si un élément existe déjà dans un tableau, sinon ajoutez seulement l’élément, sinon renvoyez le même état.
Écris-le comme ceci:
case "ADD_EVENT":
let index = state.findIndex(el => el.event_id == action.event.event_id);
if(index == -1)
return [...state, action.event];
return state;
Solution:
const eventReducer = ( state = [], action ) => {
switch (action.type) {
case 'ADD_EVENT':
return state.some(( { event_id } ) => event_id === action.event.event_id)
? state
: [...state, action.event];
default:
return state;
}
};
Tester:
const state1 = eventReducer([], {
type: 'ADD_EVENT',
event: { event_id: 1, name: 'Chelsea v Arsenal' }
});
const state2 = eventReducer(state1, {
type: 'ADD_EVENT',
event: { event_id: 2, name: 'Chelsea v Manchester' }
});
const state3 = eventReducer(state2, {
type: 'ADD_EVENT',
event: { event_id: 1, name: 'Chelsea v Arsenal' }
});
console.log(state1, state2, state3);
Vous pouvez utiliser Array.prototype.find () .
Exemple (non testé)
const eventExists = (events, event) => {
return evets.find((e) => e.event_id === event.event_id);
}
export const eventReducer = (state = [], action) = > {
switch (action.type) {
case "ADD_EVENT":
if (eventExists(state, action.event)) {
return state;
} else {
return [...state, action.event];
}
default:
return state;
}
};
Mise à jour (commentaire de CodingIntrigue))
Vous pouvez également utiliser Array.prototype.some () pour une meilleure approche
const eventExists = (events, event) => {
return evets.some((e) => e.event_id === event.event_id);
}
export const eventReducer = (state = [], action) = > {
switch (action.type) {
case "ADD_EVENT":
if (eventExists(state, action.event)) {
return state;
} else {
return [...state, action.event];
}
default:
return state;
}
};
Vous pouvez faire quelque chose comme ça, pour la partie logique, afin de vous assurer de ne pas avoir la même entrée deux fois.
const x = filter.arrayOfData(item => item.event_id !== EVENT_FROM_SOCKET);
if (x.length === 0) {
// dispatch action here
} else {
// ignore and do nothing
}
Vous devez faire attention lorsque vous utilisez des tableaux dans des réducteurs. Vous ajoutez essentiellement plus d'éléments à la liste lorsque vous appelez:
[...state, action.event]
Si vous utilisez plutôt une carte, vous pouvez éviter les doublons
const events = { ...state.events }
events[action.event.event_id] = action.event.name]
{...state, events }