Reselect is a selector library you can attach to Redux. Its role boils down to two things:
- Abstracting the part where you pull data from the store and map it when you
connecta component to Redux. - Caching the value returned by a selector function to improve performance.
Suppose you have code like this:
const mapStateToProps = (state, ownProps) => {
const { contentIds } = state.userContent;
return {
contentIds,
};
};
With Reselect you can reshape it like this:
// selector
const getUserContent = state => state.userContent;
const selectUserContentIds = createSelector(
[ getUserContent ], // input selector
userContent => userContent.contentIds
);
//component
const mapStateToProps = (state, ownProps) => ({
contentIds: selectUserContentIds(state),
});
The first obvious win is that the component doesn’t need to know the shape of the Redux store. It only needs to call the selector. Reselect also helps performance through memoized selectors.
One caveat: in a list component, each item may need different data from the selector, so memoization won’t behave as you expect. In that case wrap the selector-creation logic in a function and give each list item its own selector instance.
// selector
const getUserContent = state => state.favoriteContent;
const selectTitleByContentId = (state, contentId) => createSelector(
[ getUserContent ],
userContent => userContent.titles[contentId]
)(state);
// list item component
const mapStateToProps = (state, ownProps) => ({
title: selectTitleByContentId(state, ownProps.contentId),
});
Another feature of Reselect is composability. As shown below, an existing selector can itself become an input selector to another selector, so you can build selectors in layers.
// selector
const getUserContent = state => state.userContent;
const getEntities = state => state.entities;
const selectUserContentIds = createSelector(
[ getUserContent ], // input selector
userContent => userContent.contentIds
);
const selectUserContents = createSelector(
[ selectUserContentIds, getEntities ],
(userContentIds, entities) => userContentIds.map(contentId => entities.contents[contentId].data)
);
//component
const mapStateToProps = (state, ownProps) => ({
contents: selectUserContents(state),
});