Created
July 23, 2018 16:10
-
-
Save BlueWinds/071635379914d31bce8319868b97709d to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| // In this version, each reducer is very clear - for example, looking at billingReducer, | |
| // we know all the ways that users can get credit. If a user ends up with an invalid credit amount, | |
| // we can easily start looking in the billingReducer to know all the places this could have come | |
| // from. | |
| // On the other hand, looking at VIEW_PERFORMER, it's not clear what exactly happens when the action is | |
| // emitted. We have to go look at every reducer (or at least grep them) to know what the aciton is doing. | |
| // Also note how 'VIEW_PERFORMER' needs extra context attached - it's not clear, looking at the action creator, | |
| // why it needs purchaseHistory attached. What does that have to do with viewing a performer? | |
| // Action creator | |
| const viewPerformer = performer => (dispatch, getState) => { | |
| dispatch({ | |
| type: 'VIEW_PERFORMER', | |
| performer, | |
| purchaseHistory: getState().purchaseHistory, | |
| }); | |
| } | |
| // Reducers | |
| const performerReducer = (state, action) => { | |
| switch (action.type) { | |
| case 'VIEW_PERFORMER': | |
| return action.performer; | |
| default: | |
| return state; | |
| } | |
| } | |
| const locationReducer: (state, action) => { | |
| switch (action.type) { | |
| case 'VIEW_PERFORMER': | |
| return { | |
| ...state, | |
| location: `/cam/${action.performer.nickname}`, | |
| }; | |
| default: | |
| return state; | |
| } | |
| }; | |
| const billingReducer = (state, action) => { | |
| switch (action.type) { | |
| case 'VIEW_PERFORMER': | |
| const recentlySpentOnPerf = action.purchaseHistory.some(purchase => purchase.performer === action.performer.id); | |
| return { | |
| ...state, | |
| discount: state.discount + recentlySpentOnPerf ? 500 : 0, | |
| } | |
| default: | |
| return state; | |
| } | |
| }; | |
| // Root reducer | |
| const rootReducer = (state, action) => { | |
| return { | |
| performer: performerReducer(state, action), | |
| location: locationReducer(state, action), | |
| billing: billingReducer(state, action), | |
| purchaseHistory: purchaseHistoryReducer(state, action), // Not shown | |
| } | |
| }; |
This file contains hidden or 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
| // In this version, we know all the actions that happen when someone views a performer. | |
| // The action creator function is explicit - it says exactly what happens, so there's no mystery. | |
| // On the other hand, the reducers are far less informative. If I see that someone has discount, | |
| // there's no clue why - I have to grep the codebase to find all the places that dispatch ADD_DISCOUNT. | |
| // This can be especially tricky when debugging - if I see {type: 'ADD_DISCOUNT', amount: NaN}, that gives | |
| // me to clues why it's NaN, or where to start looking for the bad action creator. The state is no longer well | |
| // contained in just the reducers. | |
| // Action creator | |
| const viewPerformer = performer => (dispatch, getState) => { | |
| dispatch({type: 'VIEW_PERFORMER', performer}); | |
| dispatch({type: 'GOTO', url: `/cam/${performer.nickname}`}); | |
| const recentlySpentOnPerf = getState().purchaseHistory.some(purchase => purchase.performer === performer.id); | |
| if (recentlySpentOnPerf) { | |
| dispatch({type: 'ADD_DISCOUNT', amount: 500}); | |
| } | |
| } | |
| // Reducers | |
| const performerReducer = (state, action) => { | |
| switch (action.type) { | |
| case 'VIEW_PERFORMER': | |
| return action.performer; | |
| default: | |
| return state; | |
| } | |
| } | |
| const locationReducer: (state, action) => { | |
| switch (action.type) { | |
| case 'GOTO': | |
| return { | |
| ...state, | |
| url: action.url, | |
| }; | |
| default: | |
| return state; | |
| } | |
| }; | |
| const billingReducer = (state, action) => { | |
| switch (action.type) { | |
| case 'ADD_DISCOUNT': | |
| return { | |
| ...state, | |
| discount: state.discount + action.amount, | |
| }; | |
| default: | |
| return state; | |
| } | |
| } | |
| // Root reducer | |
| const rootReducer = (state, action) => { | |
| return { | |
| performer: performerReducer(state, action), | |
| location: locationReducer(state, action), | |
| billing: billingReducer(state, action), | |
| } | |
| } |
This file contains hidden or 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
| // In this version, each action type has its own reducer. This makes them very clear, since I have one and only one place to look | |
| // in order to figure out what happens during a VIEW_PERFOMER action, and that reducer has access to the entire state - | |
| // no need to explicitly pass purchaseHistory in as part of the action. | |
| // On the downside, there are no longer vertical slices of state - there's no easy way to see all the actions | |
| // which modify a specific piece of of the store. It's difficult to find all the places that modify 'billing', | |
| // since there isn't even a convenient string constant I can grep. | |
| // Action creator | |
| const viewPerformer = performerId => dispatch => { | |
| dispatch({type: 'VIEW_PERFOMER', performer}); | |
| } | |
| // Reducers | |
| const viewPerformerReducer = (state, {performer}) => { | |
| const recentlySpentOnPerf = state.purchaseHistory.some(purchase => purchase.performer === performer.id); | |
| return { | |
| performer, | |
| billing: { | |
| ...state.billing, | |
| credit: state.credit + recentlySpentOnPerf ? 500 : 0, | |
| }, | |
| location: { | |
| ...state.location, | |
| url: `/cam/${performer.nickname}`, | |
| } | |
| } | |
| } | |
| // Root reducer | |
| const rootReducer = (state, action) => { | |
| switch (action.type) { | |
| case 'VIEW_PERFOMER': | |
| return viewPerformerReducer(state, action); | |
| default: | |
| return state; | |
| } | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment