-
-
Save alexgriff/81dacf490e5237fc96bb4c312aeda91f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// adadpted from an example in Fullstack React https://www.fullstackreact.com/ | |
// ------------------------------------------------- | |
// Original Code, Deeply Nested, Reducer is Complex | |
// ------------------------------------------------- | |
// State contains an array of subjects and the id of the currently | |
// active subject. Each subject has many notes. | |
// Initially, before refactoring, the actions of adding / deleting a note are pretty messy | |
// because the state is so nested | |
// reducers/index.js | |
const initialState = [ | |
{ | |
id: 1, | |
title: 'React', | |
notes: [] | |
}, | |
{ | |
id: 2, | |
title: 'Redux', | |
notes: [] | |
}, | |
{ | |
id: 3, | |
title: 'Functional Programming', | |
notes: [] | |
}, | |
{ | |
id: 4, | |
title: 'Ruby', | |
notes: [] | |
} | |
]; | |
const reducer = (state = initialState, action) => { | |
let subjectIndex; | |
let newSubjectNotes; | |
switch (action.type) { | |
case 'ADD_NOTE': | |
subjectIndex = state.subjects.findIndex(s => s.id === action.subjectId); | |
newSubjectNotes = [...state.subjects[subjectIndex].notes, action.note]; | |
return { | |
...state, | |
subjects: [ | |
...state.subjects.slice(0, subjectIndex), | |
{ ...state.subjects[subjectIndex], notes: newSubjectNotes }, | |
...state.subjects.slice(subjectIndex + 1) | |
] | |
}; | |
case 'DELETE_NOTE': | |
subjectIndex = state.subjects.findIndex(s => s.id === action.subjectId); | |
newSubjectNotes = state.subjects[subjectIndex].notes.filter( | |
subj => subj.timestamp !== action.id | |
); | |
return { | |
...state, | |
subjects: [ | |
...state.subjects.slice(0, subjectIndex), | |
{ ...state.subjects[subjectIndex], notes: newSubjectNotes }, | |
...state.subjects.slice(subjectIndex + 1) | |
] | |
}; | |
case 'CHANGE_ACTIVE_SUBJECT': | |
return { | |
...state, | |
activeSubjectId: action.activeId | |
}; | |
default: | |
return state; | |
} | |
}; | |
// -------------------------------------------------------------------------------- | |
// Refactored Code, uses combineReducers, calls one reducer function inside another | |
// -------------------------------------------------------------------------------- | |
// no reducer will have deeply nested state | |
// ----------------- | |
// reducers/index.js | |
import { combineReducers } from 'redux'; | |
import subjects from './subjectsReducer'; | |
import activeSubjectId from './activeSubjectIdReducer'; | |
const rootReducer = combineReducers({ | |
subjects, | |
activeSubjectId | |
}); | |
export default rootReducer; | |
// ---------------------------------- | |
// reducers/activeSubjectIdReducer.js | |
const initialState = 1; | |
export default activeSubjectIdReducer = (state = initialState, action) => { | |
switch (action.type) { | |
case 'CHANGE_ACTIVE_SUBJECT': | |
return action.activeId; | |
default: | |
return state; | |
} | |
}; | |
// --------------------------- | |
// reducers/subjectsReducer.js | |
import notesReducer from './notesReducer'; | |
const initialState = [ | |
{ | |
id: 1, | |
title: 'React', | |
notes: [] | |
}, | |
{ | |
id: 2, | |
title: 'Redux', | |
notes: [] | |
}, | |
{ | |
id: 3, | |
title: 'Functional Programming', | |
notes: [] | |
}, | |
{ | |
id: 4, | |
title: 'Ruby', | |
notes: [] | |
} | |
]; | |
export default subjectsReducer = (state = initialState, action) => { | |
switch (action.type) { | |
case 'ADD_NOTE': | |
case 'DELETE_NOTE': | |
const subjectIndex = state.findIndex(s => s.id === action.subjectId); | |
const newSubjectNotes = notesReducer(state[subjectIndex].notes, action); | |
return [ | |
...state.slice(0, subjectIndex), | |
{ ...state[subjectIndex], notes: newSubjectNotes }, | |
...state.slice(subjectIndex + 1) | |
]; | |
default: | |
return state; | |
} | |
}; | |
// ------------------- | |
// src/notesReducer.js | |
export default notesReducer = (state = [], action) => { | |
switch (action.type) { | |
case 'ADD_NOTE': | |
return [...state, action.note]; | |
case 'DELETE_NOTE': | |
return state.filter(note => note.timestamp !== action.id); | |
default: | |
return state; | |
} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment