The createSelector API generates memoized selector functions. It works by taking one or more input selectors (which extract values from arguments) and a result function (which computes the derived data using those extracted values).
Key Benefits:
- Efficiency: The result function is only re-executed if the return values of the input selectors change.
- Reference Equality: If the inputs haven't changed,
createSelector returns the exact same reference as the previous call. This is critical for optimizing performance in libraries like React and React-Redux by preventing unnecessary re-renders.
Basic Pattern
const outputSelector = createSelector(
[inputSelector1, inputSelector2], // Dependencies/Input Selectors
resultFunc // Function that computes the derived value
)
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 }
]
}
// A standard selector (not memoized)
const selectCompletedTodos = (state: RootState) => {
console.log('selector ran')
return state.todos.filter(todo => todo.completed === true)
}
// A memoized selector using createSelector
const memoizedSelectCompletedTodos = createSelector(
[(state: RootState) => state.todos],
todos => {
console.log('memoized selector ran')
return todos.filter(todo => todo.completed === true)
}
)
// First call: runs the result function
memoizedSelectCompletedTodos(state) // "memoized selector ran"
// Subsequent calls with same state: returns cached result without running result function
memoizedSelectCompletedTodos(state)
// Comparison with non-memoized selector
console.log(selectCompletedTodos(state) === selectCompletedTodos(state)) // false (new array reference)
console.log(memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)) // true (same reference)