Skip to main content

unstable_autotrackMemoize

Uses an "auto-tracking" approach inspired by the work of the Ember Glimmer team. It uses a Proxy to wrap arguments and track accesses to nested fields in your selector on first read. Later, when the selector is called with new arguments, it identifies which accessed fields have changed and only recalculates the result if one or more of those accessed fields have changed. This allows it to be more precise than the shallow equality checks in lruMemoize.

danger

This API is still experimental and undergoing testing.

Design Tradeoffs

  • Pros:

    • It is likely to avoid excess calculations and recalculate fewer times than lruMemoize will, which may also result in fewer component re-renders.
  • Cons:

    • It only has a cache size of 1.
    • It is slower than lruMemoize, because it has to do more work. (How much slower is dependent on the number of accessed fields in a selector, number of calls, frequency of input changes, etc)
    • It can have some unexpected behavior. Because it tracks nested field accesses, cases where you don't access a field will not recalculate properly. For example, a badly-written selector like:
    createSelector([state => state.todos], todos => todos)

    that just immediately returns the extracted value will never update, because it doesn't see any field accesses to check.

Use Cases

  • It is likely best used for cases where you need to access specific nested fields in data, and avoid recalculating if other fields in the same data objects are immutably updated.

Parameters

NameDescription
funcThe function to be memoized.

Returns

A memoized function with a .clearCache() method attached.

Type Parameters

NameDescription
FuncThe type of the function that is memoized.

Examples

Using unstable_autotrackMemoize with createSelector

unstable_autotrackMemoize/usingWithCreateSelector.ts
import { createSelector, unstable_autotrackMemoize } from 'reselect'

export interface RootState {
todos: { id: number; completed: boolean }[]
alerts: { id: number; read: boolean }[]
}

const selectTodoIds = createSelector(
[(state: RootState) => state.todos],
todos => todos.map(todo => todo.id),
{ memoize: unstable_autotrackMemoize }
)

Using unstable_autotrackMemoize with createSelectorCreator

unstable_autotrackMemoize/usingWithCreateSelectorCreator.ts
import { createSelectorCreator, unstable_autotrackMemoize } from 'reselect'
import type { RootState } from './usingWithCreateSelector'

const createSelectorAutotrack = createSelectorCreator({
memoize: unstable_autotrackMemoize
})

const selectTodoIds = createSelectorAutotrack(
[(state: RootState) => state.todos],
todos => todos.map(todo => todo.id)
)