website/docs/introduction/getting-started.mdx
import { InternalLinks } from '@site/src/components/InternalLinks' import { ExternalLinks } from '@site/src/components/ExternalLinks' import PackageTabs from '@site/src/components/PackageManagerTabs' import Tabs from '@theme/Tabs' import TabItem from '@theme/TabItem' import Link from '@docusaurus/Link'
A library for creating memoized "selector" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.
The Redux docs usage page on <Link to="https://redux.js.org/usage/deriving-data-selectors">Deriving Data with Selectors</Link> covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with <ExternalLinks.ReactRedux />.
While Reselect is not exclusive to <ExternalLinks.Redux />, it is already included by default in <ExternalLinks.ReduxToolkit text='the official Redux Toolkit package' /> - no further installation needed.
import { createSelector } from '@reduxjs/toolkit'
For standalone usage, install the reselect package:
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 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 <Link to='https://codesandbox.io/s/reselect-example-g3k9gf?file=/src/index.js'>this CodeSandbox</Link>:
<Tabs groupId='language' defaultValue='ts' values={[ {label: 'TypeScript', value: 'ts'}, {label: 'JavaScript', value: 'js'}, ]}> <TabItem value='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
import { createSelector } from 'reselect'
const state = {
todos: [
{ id: 0, completed: false },
{ id: 1, completed: true }
],
alerts: [
{ id: 0, read: false },
{ id: 1, read: true }
]
}
const selectCompletedTodos = state => {
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 => 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.
The below example serves as a visual aid:
const outputSelector = createSelector(
[inputSelector1, inputSelector2, inputSelector3], // synonymous with `dependencies`.
resultFunc // Result function
)