Last active
November 14, 2024 16:58
-
-
Save jslatts/1c5d4d46b6e5b0ac0e917fa3b6f7968f to your computer and use it in GitHub Desktop.
Utility to bind selectors to a slice of state. Helpful for keeping things DRY when colocating selectors and reducers
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
// Example of usage | |
import { selectors } from './rootReducer'; | |
import { selectors } from '../../reducers/rootReducer'; | |
const mapStateToProps = (state: State, ownProps: any) => ({ | |
theseObjects: selectors.getTheseObjects(state), | |
thoseObjects: selectors.getThoseObjects(state), | |
showSomethinginUi: selectors.getSomethingFromUiSelectors(state), | |
}); | |
... MORE CODE ... |
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
// @flow | |
// Helper to wrap a redux selector with a predetermined state slice function | |
'use strict'; | |
export const bindSelectors = (slicer: (any) => any, selectors: *) => { | |
const keys = Object.keys(selectors); | |
const boundMethods = {}; | |
keys.forEach(k => { | |
boundMethods[k] = fullState => selectors[k](slicer(fullState)); | |
}); | |
return boundMethods; | |
}; | |
export default bindSelectors; |
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
// Example root reducer | |
import { bindSelectors } from './bindSelectors'; | |
import ui, { selectors as uiSelectors } from './ui'; | |
import theseObjects, { selectors as theseObjectSelectors } from './theseObjectsReducers'; | |
import thoseObjects, { selectors as thoseObjectSelectors } from './thoseObjectsReducers'; | |
// State shape looks like | |
const defaultState = { | |
ui, | |
theseObjects, | |
thoseObjects, | |
}; | |
... | |
REDUCER CODE GOES HERE | |
... | |
export default rootReducer; | |
// bindSelectors binds a state slice to the sub-reducer's selectors | |
export const selectors = { | |
...bindSelectors(state => state.theseObjects, theseObjectSelectors), | |
...bindSelectors(state => state.thoseObjects, thoseObjectSelectors), | |
...bindSelectors(state => state.ui, uiSelectors), | |
}; |
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
// Example theseObjects reducer | |
... | |
REDUCER CODE GOES HERE | |
... | |
export default theseObjects; | |
// Seletors in this file do not have to worry about what the state of the whole state tree looks like | |
// They just operate within the same scope of their corresponding reducers | |
export const selectors = { | |
getFilteredObjects: (state: State) => state.filter(t => t.someFlag === true), | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@jslatts the
selectors
object that is exported fromrootReducer.js
could introduce a subtle bug if two slices of state define selectors with the same name.Instead of spreading all selectors for each slice into a single object, you might consider namespacing them