开始使用 Reselect
一个用于创建 memoized "selector" 函数的库。常与 Redux 一起使用,但也可以与任何普通的 JS 不可变数据一起使用。
- Selectors 可以计算派生数据,允许 Redux 存储最小可能的状态。
- Selectors 是高效的。除非其中一个参数发生变化,否则不会重新计算 selector。
- Selectors 是可组合的。它们可以作为其他 selectors 的输入。
Redux 文档的 使用 Selectors 派生数据 页面涵盖了 selectors 的目的和动机,为什么 memoized selectors 是有用的,典型的 Reselect 使用模式,以及如何与 React-Redux 一起使用 selectors。
安装
Redux Toolkit
虽然 Reselect 不仅限于 Redux,但它已经默认包含在 官方的 Redux Toolkit 包 中 - 无需进一步安装。
import { createSelector } from '@reduxjs/toolkit'
独立使用
对于独立使用,安装 reselect
包:
- NPM
- Yarn
- Bun
- PNPM
npm install reselect
yarn add reselect
bun add reselect
pnpm add reselect
基本使用
Reselect 导出了一个 createSelector
API,用于生成 memoized selector 函数。createSelector
接受一个或多个输入 selectors,这些 selectors 从参数中提取值,以及一个结果函数,该函数接收提取的值并应返回一个派生值。如果多次调用生成的输出 selector,只有在提取的值发生变化时,输出才会被重新计算。
你可以在以下 示例 中尝试 这个 CodeSandbox:
- TypeScript
- JavaScript
basicUsage.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) // 选择器运行
selectCompletedTodos(state) // 选择器运行
selectCompletedTodos(state) // 选择器运行
const memoizedSelectCompletedTodos = createSelector(
[(state: RootState) => state.todos],
todos => {
console.log('记忆选择器运行')
return todos.filter(todo => todo.completed === true)
}
)
memoizedSelectCompletedTodos(state) // 运行了记忆化的选择器
memoizedSelectCompletedTodos(state)
memoizedSelectCompletedTodos(state)
console.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false
console.log(
memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)
) //=> true
basicUsage.js
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) // 选择器运行
selectCompletedTodos(state) // 选择器运行
selectCompletedTodos(state) // 选择器运行
const memoizedSelectCompletedTodos = createSelector(
[state => state.todos],
todos => {
console.log('memoized selector ran')
return todos.filter(todo => todo.completed === true)
}
)
memoizedSelectCompletedTodos(state) // 运行了记忆化的选择器
memoizedSelectCompletedTodos(state)
memoizedSelectCompletedTodos(state)
console.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false
console.log(
memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)
) //=> true
如上例所示,memoizedSelectCompletedTodos
在第二次或第三次运行时不会运行,但我们仍然得到与上次相同的返回值。
除了跳过不必要的重新计算,memoizedSelectCompletedTodos
如果没有重新计算,将返回现有的结果引用。这对于像 React-Redux 或 React 这样经常依赖引用相等性检查来优化 UI 更新的库来说非常重要。
术语
- Selector 函数 : 一个接受一个或多个 JavaScript 值作为参数,并派生出结果的函数。当与 Redux 一起使用时,第一个参数通常是整个 Redux store 状态。
-
输入 Selectors
: 用作创建 memoized selector 的基础构建块的基本 selector 函数。它们作为第一个参数传递给
createSelector
,并带有所有 selector 参数。它们负责提取和提供必要的值给 result function。 -
输出 Selector
: 由
createSelector
创建的实际 memoized selectors。 - 结果函数 : 在 input selectors 之后的函数。它接受 input selectors 的返回值作为参数并返回结果。
- 依赖项 : 与 input selectors 相同。它们是 output selector "依赖" 的内容。
下面的例子可以作为一个视觉辅助:
const outputSelector = createSelector(
[inputSelector1, inputSelector2, inputSelector3], // 与 `依赖项` 同义。
resultFunc // 结果函数
)