Reputation: 1931
In my Angular2 application, I use ngrx to manage states, so when I receive data from the server, I dispatch an action to a reducer.
MyExampleReducer.ts :
export const Reviews: ActionReducer<any> = (state: any[] = [], action: Action) => {
switch (action.type) {
case GET_REVIEWS:
return action.payload;
case ADD_REVIEW :
return [...state, {review : action.payload, replays : []}];
case UPDATE_REVIEW:
return '' // return what ?
case DELETE_REVIEW:
return state.filter(item => {
return item.id !== action.payload.id;
});
default:
return state;
}
};
The problem is when i have to update an item in my Reviews array, what is the best way to do in the redux way ?
Upvotes: 5
Views: 5888
Reputation: 826
Assuming that your state is just an array full of reviews you could do the following:
export const Reviews: ActionReducer<any> = (state: any[] = [], action: Action) => {
switch (action.type) {
case GET_REVIEWS:
return action.payload;
case ADD_REVIEW :
return [...state, {review : action.payload, replays : []}];
case UPDATE_REVIEW:
// get an array of all ids and find the index of the required review
let index = state.map(review => review.id)
.indexOf(action.payload.id);
return [
...state.slice(0, index),
Object.assign({}, state[index], action.payload),
...state.slice(index + 1)
]
case DELETE_REVIEW:
return state.filter(item => {
return item.id !== action.payload.id;
});
default:
return state;
}
First you need to find the index of the review that should be updated. After that you can create a new array where you replace the object at the index's position.
A great resource for this kind of mutations is this video.
Upvotes: 4
Reputation: 58400
You can use map
to return an array that has the element that corresponds to the action updated:
export const Reviews: ActionReducer<any> = (state: any[] = [], action: Action) => {
switch (action.type) {
case ADD_REVIEW:
return [...state, { review: action.payload, replays: [] }];
case UPDATE_REVIEW:
return state.map(item => item.id === action.payload.id ? { review: action.payload, replays: [] } : item);
case DELETE_REVIEW:
return state.filter(item => item.id !== action.payload.id);
default:
return state;
}
}
Also, you can simplify the reviews reducer by using the review reducer to perform the ADD_REVIEW
and UPDATE_REVIEW
actions - the reviews reducer is then only concerned with managing the list of reviews and not the reviews themselves:
import { reviewReducer } from '...';
export const Reviews: ActionReducer<any> = (state: any[] = [], action: Action) => {
switch (action.type) {
case ADD_REVIEW:
return [...state, reviewReducer(undefined, action)];
case UPDATE_REVIEW:
return state.map(item => item.id === action.payload.id ? reviewReducer(item, action) : item);
case DELETE_REVIEW:
return state.filter(item => item.id !== action.payload.id);
default:
return state;
}
}
Upvotes: 5