跳到主要内容

createSelector

接受一个或多个"input selectors"(作为单独的参数或单个数组), 一个"result function",以及一个可选的选项对象, 并生成一个备忘录选择器函数。

Redux 文档的 使用选择器派生数据 页面介绍了选择器的目的和动机,为什么备忘录选择器有用,以及典型的 Reselect 使用模式。

const selectTodosByCategory = createSelector(
[
// 传递带有类型参数的输入选择器
(state: RootState) => state.todos,
(state: RootState, category: string) => category
],
// 提取的值被传递给结果函数进行重新计算
(todos, category) => {
return todos.filter(t => t.category === category)
}
)

参数

名称描述
inputSelectors一个 input selectors 数组,也可以作为单独的参数传递。
resultFunc一个函数,它接受 input selectors 的结果作为单独的参数。
createSelectorOptions?一个可选的选项对象,允许进一步自定义每个选择器。

返回

一个备忘录的 output selector

输出选择器字段

createSelector 创建的输出选择器附加了几个额外的属性:

名称描述
resultFunc传递给 createSelector 的最终函数。
memoizedResultFuncresultFunc 的记忆版本。
lastResult返回 memoizedResultFunc 计算的最后结果。
dependenciescreateSelector 用来组成 resultFunc 的输入选择器数组。
recomputations计算 memoizedResultFunc 重新计算的次数。
resetRecomputationsrecomputations 的计数重置为 0。
dependencyRecomputations计算 input selectors (dependencies) 重新计算的次数。这与 recomputations 不同,后者跟踪的是 result function 的重新计算次数。
resetDependencyRecomputationsdependencyRecomputations 的计数重置为 0。
memoize用于记忆 resultFunc 的函数。
argsMemoize用于记忆传入 output selector 的参数的函数。

类型参数

名称描述
InputSelectorsinput selectors 数组的类型。
Resultresult function 以及 output selector 的返回类型。
OverrideMemoizeFunction可以传入选项对象的可选 memoize 函数的类型,以覆盖最初传入 createSelectorCreator 的原始 memoize 函数。
OverrideArgsMemoizeFunction可以传入选项对象的可选 argsMemoize 函数的类型,以覆盖最初传入 createSelectorCreator 的原始 argsMemoize 函数。

定义预设类型的 createSelector

从 Reselect 5.1.0 开始,你可以创建一个预设 state 类型的 createSelector 版本。这允许你一次设置 state 类型,从而无需在每次调用 createSelector 时指定它。

要做到这一点,你可以调用 createSelector.withTypes<StateType>()

createSelector/withTypes.ts
import { createSelector } from 'reselect'

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

export const createAppSelector = createSelector.withTypes<RootState>()

const selectTodoIds = createAppSelector(
[
// `state`的类型被设置为`RootState`,无需手动设置类型
state => state.todos
],
todos => todos.map(({ id }) => id)
)

导入并使用预定义的 createAppSelector 替代原始的,状态的类型将会自动使用。

已知的限制

目前这种方法只有在输入选择器作为单一数组提供时才有效。

如果你将输入选择器作为单独的内联参数传递,结果函数的参数类型将不会被推断。 作为解决方案,你可以:

  1. 将你的输入选择器包装在一个单一数组中
  2. 你可以注解结果函数的参数类型:
createSelector/annotateResultFunction.ts
import { createSelector } from 'reselect'

interface Todo {
id: number
completed: boolean
}

interface Alert {
id: number
read: boolean
}

export interface RootState {
todos: Todo[]
alerts: Alert[]
}

export const createAppSelector = createSelector.withTypes<RootState>()

const selectTodoIds = createAppSelector(
// `state`的类型被设置为`RootState`,无需手动设置类型
state => state.todos,
// ❌ 已知的限制:在这种情况下,参数类型不会被推断,
// 因此你需要手动注解它们。
(todos: Todo[]) => todos.map(({ id }) => id)
)
提示

你也可以使用这个API与createSelectorCreator来创建一个预定义类型的自定义选择器创建器:

createSelector/createAppSelector.ts
import microMemoize from 'micro-memoize'
import { shallowEqual } from 'react-redux'
import { createSelectorCreator, lruMemoize } from 'reselect'

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

export const createAppSelector = createSelectorCreator({
memoize: lruMemoize,
argsMemoize: microMemoize,
memoizeOptions: {
maxSize: 10,
equalityCheck: shallowEqual,
resultEqualityCheck: shallowEqual
},
argsMemoizeOptions: {
isEqual: shallowEqual,
maxSize: 10
},
devModeChecks: {
identityFunctionCheck: 'never',
inputStabilityCheck: 'always'
}
}).withTypes<RootState>()

const selectReadAlerts = createAppSelector(
[
// `state`的类型被设置为`RootState`,无需手动设置类型
state => state.alerts
],
alerts => alerts.filter(({ read }) => read)
)