Created
May 15, 2019 15:16
-
-
Save MrLeebo/1e5338b20b0ffad7a1d2f42e4ba1a707 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
/// action creators //////////////////////////////////////////////////////////// | |
// exposing action creators as functions so the caller doesn't have to worry | |
// about typos when dispatching actions; e.g. dispatch(clear()) | |
// mark in state that the refetch is being performed | |
export const beginFetch = payload => ({ type: 'beginFetch', payload }) | |
// request a new refetch | |
export const refetch = () => ({ type: 'refetch' }) | |
// update state with the results from a fetch | |
export const set = payload => ({ type: 'set', payload }) | |
// requests a refetch and removes any requests that are not in-flight | |
export const clear = () => ({ type: 'clear' }) | |
/// reducers /////////////////////////////////////////////////////////////////// | |
// if one big switch statement isn't your style, you can create a handler object | |
// which is basically just a bunch of small reducers that gets invoked by your | |
// main reducer. | |
const handlers = { | |
beginFetch: beginFetchReducer, | |
refetch: refetchReducer, | |
set: setReducer, | |
clear: clearReducer | |
} | |
function beginFetchReducer(state, {payload}) { | |
return { ...state, performRefetch: false, previousOptions: payload } | |
} | |
function refetchReducer(state, action) { | |
return { ...state, performRefetch: true } | |
} | |
// with reducers, we want the state to be immutable, which means we end up | |
// bending over backwards to permute the state without mutating the original | |
// state object. That leads to ugly code like this with lots of spread operators. | |
// As reducers get more complex, this strategy doesn't scale up very well. | |
// A library like immer can make it help when that happens | |
function setReducer(state, action) { | |
const { url, options, ...params } = action.payload | |
return { | |
...state, | |
requests: { ...state.requests, [requestKeyFrom(url, options)]: params } | |
} | |
} | |
function clearReducer(state, action) { | |
return { | |
...state, | |
performRefetch: true, | |
requests: _.filter(state, { isLoading: true }) | |
} | |
} | |
// the primary reducer, which just invokes one of the handlers based on the type | |
function reducer(state, action) { | |
if (!handlers[action.type]) { | |
throw new Error(`Unrecognized action: ${action.type}`) | |
} | |
return handlers[action.type](state, action) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
As an example of using "immer" to write a reducer, you can do something like
you make the changes in an imperative fashion, but immer actually proxies your changes and clones the objects you're mutating so you get behavior like the { ...state } code without having to keep track of what to clone yourself.