Selectors for Redux.
npm install reselectts
import { createSelector } from '@reduxjs/toolkit'
`
$3
For standalone usage, install the reselect package:
`bash
NPM
npm install reselect
Yarn
yarn add reselect
`
---
Documentation
The Reselect docs are available at https://reselect.js.org, and include usage guides and API references:
- Introduction
- How Does Reselect Work?
- API Reference:
- [createSelector]
- [createSelectorCreator]
- [createStructuredSelector]
- Development-Only Stability Checks
- [lruMemoize]
- [weakMapMemoize]
- FAQ
Basic Usage
Reselect exports a [createSelector] API, which generates memoized selector functions. [createSelector] accepts one or more [input selectors], which extract values from arguments, and a [result function] function that receives the extracted values and should return a derived value. If the generated [output selector] is called multiple times, the output will only be recalculated when the extracted values have changed.
You can play around with the following example in this CodeSandbox:
`ts
import { createSelector } from 'reselect'
interface RootState {
todos: { id: number; completed: boolean }[]
alerts: { id: number; read: boolean }[]
}
const state: RootState = {
todos: [
{ id: 0, completed: false },
{ id: 1, completed: true }
],
alerts: [
{ id: 0, read: false },
{ id: 1, read: true }
]
}
const selectCompletedTodos = (state: RootState) => {
console.log('selector ran')
return state.todos.filter(todo => todo.completed === true)
}
selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran
const memoizedSelectCompletedTodos = createSelector(
[(state: RootState) => state.todos],
todos => {
console.log('memoized selector ran')
return todos.filter(todo => todo.completed === true)
}
)
memoizedSelectCompletedTodos(state) // memoized selector ran
memoizedSelectCompletedTodos(state)
memoizedSelectCompletedTodos(state)
console.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false
console.log(
memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)
) //=> true
`
As you can see from the example above, memoizedSelectCompletedTodos does not run the second or third time, but we still get the same return value as last time.
In addition to skipping unnecessary recalculations, memoizedSelectCompletedTodos returns the existing result reference if there is no recalculation. This is important for libraries like [React-Redux] or [React] that often rely on reference equality checks to optimize UI updates.
---
Terminology
- Selector Function: A function that accepts one or more JavaScript values as arguments, and derives a result. When used with [Redux], the first argument is typically the entire Redux store state.
- input selectors: Basic selector functions used as building blocks for creating a memoized selector. They are passed as the first argument(s) to [createSelector], and are called with all selector arguments. They are responsible for extracting and providing necessary values to the [result function].
- Output Selector: The actual memoized selectors created by [createSelector].
- Result Function: The function that comes after the [input selectors]. It takes the [input selectors]' return values as arguments and returns a result.
- Dependencies: Same as [input selectors]. They are what the [output selector] "depends" on.
The below example serves as a visual aid:
`ts
const outputSelector = createSelector(
[inputSelector1, inputSelector2, inputSelector3], // synonymous with dependencies.
resultFunc // Result function
)
`
---
What's New in 5.0.0?
Version 5.0.0 introduces several new features and improvements:
- Customization Enhancements:
- Added the ability to pass an options object to [createSelectorCreator], allowing for customized memoize and argsMemoize functions, alongside their respective options (memoizeOptions and argsMemoizeOptions).
- The [createSelector] function now supports direct customization of memoize and argsMemoize within its options object.
- Memoization Functions:
- Introduced new experimental memoization functions: weakMapMemoize and unstable_autotrackMemoize.
- Incorporated memoize and argsMemoize into the [output selector fields] for debugging purposes.
- TypeScript Support and Performance:
- Discontinued support for TypeScript versions below 4.7, aligning with modern TypeScript features.
- Significantly improved TypeScript performance for nesting [output selectors][output selector]. The nesting limit has increased from approximately 8 to around 30 [output selectors][output selector], greatly reducing the occurrence of the infamous Type instantiation is excessively deep and possibly infinite error.
- Selector API Enhancements:
- Removed the second overload of createStructuredSelector due to its susceptibility to runtime errors.
- Additional Functionalities:
- Added dependencyRecomputations and resetDependencyRecomputations to the [output selector fields]. These additions provide greater control and insight over [input selectors], complementing the new argsMemoize API.
- Introduced inputStabilityCheck, a development tool that runs the [input selectors] twice using the same arguments and triggers a warning If they return differing results for the same call.
- Introduced identityFunctionCheck, a development tool that checks to see if the [result function] returns its own input.
These updates aim to enhance flexibility, performance, and developer experience. For detailed usage and examples, refer to the updated documentation sections for each feature.
- Breaking Changes:
- Removed ParametricSelector and OutputParametricSelector types. Their functionalities are now integrated into Selector and OutputSelector respectively, which inherently support additional parameters.
---
License
MIT
References
Click to Expand
Originally inspired by getters in NuclearJS, subscriptions in re-frame and this proposal from speedskater.
[typescript-badge]: https://img.shields.io/badge/TypeScript-v4%2E7%2B-007ACC?style=for-the-badge&logo=TypeScript&logoColor=black&labelColor=blue&color=gray
[build-badge]: https://img.shields.io/github/actions/workflow/status/reduxjs/reselect/build-and-test-types.yml?branch=master&style=for-the-badge
[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml
[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=for-the-badge
[npm]: https://www.npmjs.org/package/reselect
[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=for-the-badge
[coveralls]: https://coveralls.io/github/reduxjs/reselect
[Redux]: https://redux.js.org 'Redux'
[React]: https://react.dev 'React'
[React-Redux]: https://react-redux.js.org 'React-Redux'
[selector]: #selector-function 'Selector Function'
[input selectors]: #input-selectors 'Input Selectors'
[output selector]: #output-selector 'Output Selector'
[result function]: #result-function 'Result Function'
[output selector fields]: https://reselect.js.org/api/createSelector#output-selector-fields 'Output Selector Fields'
[createSelector]: https://reselect.js.org/api/createSelector 'createSelector'
[createSelectorCreator]: https://reselect.js.org/api/createSelectorCreator 'createSelectorCreator'
[lruMemoize]: https://reselect.js.org/api/lruMemoize 'lruMemoize'
[weakMapMemoize]: https://reselect.js.org/api/weakMapMemoize 'weakMapMemoize'
[createStructuredSelector`]: https://reselect.js.org/api/createStructuredSelector 'createStructuredSelector'