'prevent duplicate objects being added to state react redux
I have a question regarding preventing duplicates from being added to my redux store.
It should be straight forward but for some reason nothing I try is working.
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;
}
};
The action looks something like the below:
{
type: "ADD_EVENT",
event: { event_id: 1, name: "Chelsea v Arsenal" }
}
The issue is that on occasions the API I am working with is sending over identical messages through a websocket, which means that two identical events are getting added to my store.
I have taken many approaches but cannot figure out how to get this to work. I have tried many SO answers,
Solution 1:[1]
You can use Array.prototype.find().
Example (Not tested)
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;
}
};
Update (@CodingIntrigue's comment)
You can also use Array.prototype.some() for a better approach
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;
}
};
Solution 2:[2]
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;
}
};
Test:
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);
Solution 3:[3]
You can something like this, for the logic part to ensure you don't get the same entry twice.
const x = filter.arrayOfData(item => item.event_id !== EVENT_FROM_SOCKET);
if (x.length === 0) {
// dispatch action here
} else {
// ignore and do nothing
}
Solution 4:[4]
You need to be careful when using Arrays in reducers. You are essentially adding more items to the list when you call:
[...state, action.event]
If you instead use a map then you can prevent duplicates
const events = { ...state.events }
events[action.event.event_id] = action.event.name]
{...state, events }
Solution 5:[5]
If duplicate exist in previous state then we should return same state else update the state
case "ADDPREVIEW":
let index = state.preview.findIndex(dup => dup.id == action.payload.id);
return {
...state,
preview: index == -1 ? [...state.preview,action.payload]:[...state.preview]
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Ivan Nikitovic |
| Solution 3 | Adeel Imran |
| Solution 4 | Peter |
| Solution 5 | KARTHIKEYAN.A |
