Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

reselect

reduxjs27.9mMIT5.1.1TypeScript support: included

Selectors for Redux.

react, redux

readme

Reselect

npm packageCoverallsGitHub Workflow StatusTypeScript

A library for creating memoized "selector" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.

  • Selectors can compute derived data, allowing Redux to store the minimal possible state.
  • Selectors are efficient. A selector is not recomputed unless one of its arguments changes.
  • Selectors are composable. They can be used as input to other selectors.

The Redux docs usage page on Deriving Data with Selectors covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with React-Redux.

Installation

Redux Toolkit

While Reselect is not exclusive to Redux, it is already included by default in the official Redux Toolkit package - no further installation needed.

import { createSelector } from '@reduxjs/toolkit'

Standalone

For standalone usage, install the reselect package:

# 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:

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:

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

The below example serves as a visual aid:

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. The nesting limit has increased from approximately 8 to around 30 output selectors, 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

<summary>Click to Expand</summary>

Originally inspired by getters in NuclearJS, subscriptions in re-frame and this proposal from speedskater.

changelog

Change log

Changes in this project are primarily documented in the Github release notes:

Changes from v4.0.0 and earlier are documented in this file

This project adheres to Semantic Versioning.

v4.0.0 - 2018/09/30

New Features

Exposed selector dependencies (#251)
Use provided memoize function for selectors (#297)

Breaking Changes

Updated TypeScript typings (#274, #315)

v3.0.0 - 2017/03/24

New Features

Performance improvements (thanks to @johnhaley81)
Updated Typescript typings (thanks to everyone who helped)

Breaking Changes

For performance reasons, a selector is now not recalculated if its input is equal by reference (===).

Example:

import { createSelector } from 'reselect'

const mySelector = createSelector(
  state => state.values.filter(val => val < 5),
  values => {
    console.log('calling..')
    return values.reduce((acc, val) => acc + val, 0)
  }
)

var createSelector = require('./dist/reselect.js').createSelector

const mySelector = createSelector(
  state => state.values.filter(val => val < 5),
  values => {
    console.log('calling..')
    return values.reduce((acc, val) => acc + val, 0)
  }
)

var state1 = { values: [1, 2, 3, 4, 5, 6, 7, 8, 9] }
console.log(mySelector(state1))
state1.values = [3, 4, 5, 6, 7, 8, 9]
console.log(mySelector(state1))
var state2 = { values: [1, 2, 3, 4, 5, 6, 7, 8, 9] }
console.log(mySelector(state2))
var state3 = { values: [3, 4, 5, 6, 7] }
console.log(mySelector(state3))

Output in v2.5.4:

calling..
10
calling..
7
calling..
10
calling..
7

Output in v3.0.0:

calling..
10
10
calling..
10
calling..
7

v2.5.4 - 2016/09/17

Bug Fixes

Improve performance of defaultMemoize when using custom equality check. (#170)

v2.5.3 - 2016/07/04

Bug Fixes

Reverts a Typescript change that was a breaking change. It will be reinstated in a major release. (#145)

v2.5.2 - 2016/07/03

Bug Fixes

When a selector uses defaultMemoize, if an exception is thrown for a set of arguments then the selector should also throw when called again with those arguments. (#144)

v2.5.1 - 2016/04/21

Bug Fixes

Include es directory in package.json (#117)

v2.5.0 - 2016/04/21

New features

Add jsnext build (#116)

v2.4.0 - 2016/04/16

New features

Add umd build (#112)

v2.3.0 - 2016/04/07

New features

Add resultFunc property to selectors (#92)

v2.2.0 - 2016/03/15

New features

Add Typescript typings to package.json (#94)

v2.1.0 - 2016/03/03

New features

Add resetRecomputations method to selectors (#90)

v2.0.3 - 2016/02/01

New features

Fix bug (#78) in defaultMemoize which could cause the memoized value to be mistakenly returned for variadic functions.

v2.0.2 - 2016/01/14

New features

Fix IE8 support by compiling in 'loose' mode

v2.0.1 - 2015/11/08

Chore

Update README and github links since move to reduxjs.

v2.0.0 - 2015/10/02

Breaking Changes

createSelector, createStructuredSelector, and custom selector creators check arguments

Input selectors are now verified to be functions during selector creation. If verification fails an error is thrown, allowing for a useful stack trace

There is a small chance that this could cause a breaking change in code that contains a faulty selector that is never called.

v1.1.0 - 2015/09/16

New features

createStructuredSelector

createStructuredSelector is a convenience function that helps with a common pattern when using Reselect. The selector passed to a connect decorator often just takes other selectors and maps them to keys in an object:

const mySelectorA = state => state.a
const mySelectorB = state => state.b

const structuredSelector = createSelector(
  mySelectorA,
  mySelectorB,
  mySelectorC,
  (a, b, c) => ({
    a,
    b,
    c
  })
)

createStructuredSelector takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the inputSelectors argument, but with the selectors replaced with their values.

const mySelectorA = state => state.a
const mySelectorB = state => state.b

const structuredSelector = createStructuredSelector({
  x: mySelectorA,
  y: mySelectorB
})

const result = structuredSelector({ a: 1, b: 2 }) // will produce {x: 1, y: 2}

v1.0.0 - 2015/09/09

Breaking Changes

If upgrading from 0.0.2, see the release notes for v1.0.0-alpha

v1.0.0-alpha2 - 2015/09/01

New features

src directory included in npm package js:next field added to package.json

v1.0.0-alpha - 2015/09/01

Breaking Changes

createSelectorCreator takes a user specified memoize function instead of a custom valueEqualsFunc.

Before

import { isEqual } from 'lodash'
import { createSelectorCreator } from 'reselect'

const deepEqualsSelectorCreator = createSelectorCreator(isEqual)

After

import { isEqual } from 'lodash'
import { createSelectorCreator, defaultMemoize } from 'reselect'

const deepEqualsSelectorCreator = createSelectorCreator(defaultMemoize, isEqual)

New features

Variadic Dependencies

Selector creators can receive a variadic number of dependencies as well as an array of dependencies.

Before

const selector = createSelector(
  [state => state.a, state => state.b],
  (a, b) => a * b
)

After

const selector = createSelector(
  state => state.a,
  state => state.b,
  (a, b) => a * b
)

Access ownProps in Selector

Selector dependencies can receive a variadic number of parameters allowing a selector to receive ownProps passed from mapToProps in connect.

const selector = createSelector(
  state => state.a,
  (state, props) => state.b * props.c,
  (_, props) => props.d,
  (a, bc, d) => a + bc + d
)

Configurable Memoize Function

import { createSelectorCreator } from 'reselect'
import memoize from 'lodash.memoize'

let called = 0
const customSelectorCreator = createSelectorCreator(memoize, JSON.stringify)
const selector = customSelectorCreator(
  state => state.a,
  state => state.b,
  (a, b) => {
    called++
    return a + b
  }
)
assert.equal(selector({ a: 1, b: 2 }), 3)
assert.equal(selector({ a: 1, b: 2 }), 3)
assert.equal(called, 1)
assert.equal(selector({ a: 2, b: 3 }), 5)
assert.equal(called, 2)