Refactoring Reducers - Tuong-Nguyen/JavaScript-Structure GitHub Wiki
Reusable utility functions
- Utilities to handle the "slice-of-state" logic for the top-level app reducer
- Put all functions to a single file
reducerUtilities.js
updateObject
function updateObject(oldObject, newValues) {
// Encapsulate the idea of passing a new object as the first parameter
// to Object.assign to ensure we correctly copy data instead of mutating
return Object.assign({}, oldObject, newValues);
}
updateItemInArray
function updateItemInArray(array, itemId, updateItemCallback) {
const updatedItems = array.map(item => {
if(item.id !== itemId) {
// Since we only want to update one item, preserve all others as they are now
return item;
}
// Use the provided callback to create an updated item
const updatedItem = updateItemCallback(item);
return updatedItem;
});
return updatedItems;
}
createReducer
function createReducer(initialState, handlers) {
return function reducer(state = initialState, action) {
if (handlers.hasOwnProperty(action.type)) {
return handlers[action.type](state, action)
} else {
return state
}
}
}
How to use
- Move each case in reducer to a function
// Case reducer
function addTodo(todosState, action) {
const newTodos = todosState.concat({
id: action.id,
text: action.text,
completed: false
});
return newTodos;
}
// Case reducer
function editTodo(todosState, action) {
const newTodos = updateItemInArray(todosState, action.id, todo => {
return updateObject(todo, {text : action.text});
});
return newTodos;
}
- Use
createReducer
function to slide reducer
const todosReducer = createReducer([], {
'ADD_TODO' : addTodo,
'EDIT_TODO' : editTodo
});
- Combine reducers as usual in
rootReducer.js
// "Root reducer"
const appReducer = combineReducers({
// ...
todos : todosReducer
});