Reselect选择器记忆化中对象输入的缓存有效性疑问
Reselect选择器记忆化的常见疑问解答
Redux官网发布了一篇关于使用Reselect库实现选择器记忆化的文章,文中给出如下示例代码:
const state = { a: { first: 5 }, b: 10 } const selectA = state => state.a const selectB = state => state.b const selectA1 = createSelector([selectA], a => a.first) const selectResult = createSelector([selectA1, selectB], (a1, b) => { console.log('Output selector running') return a1 + b }) const result = selectResult(state) // Log: "Output selector running" console.log(result) // 15 const secondResult = selectResult(state) // No log output console.log(secondResult) // 15
该示例整体易懂,但存在一个疑问:Redux文档指出:
当调用选择器时,Reselect会运行所有传入的输入选择器,检查返回值。若任意结果与之前的结果不全等(===),则会重新运行输出选择器,并将这些结果作为参数传入。
那如果给selectA1提供state.a这类对象作为输入选择器的返回值,是否会每次都无法通过===检查,导致a => a.first函数每次都执行?
你的理解有偏差,核心在于对象的全等检查是基于引用的:
- 在示例中,两次调用
selectResult传入的是同一个state对象,state.a的引用完全没有变化。因此selectA返回的对象引用和上一次调用时的返回值是全等的(===成立)。 - Reselect检测到输入选择器的返回值没有变化,就会直接返回
selectA1之前缓存的结果(也就是5),不会重新执行a => a.first这个函数。
只有当state.a的引用发生改变时(比如通过state.a = {first: 5}这种方式替换成新对象),selectA的返回值才会和之前的缓存值不全等,这时候selectA1才会重新执行输出函数计算新的结果。
额外补充:如果只是修改state.a内部的属性(比如state.a.first = 6),但state.a的引用没变化,Reselect会认为输入没有改变,selectA1会继续返回旧的缓存值,这也是为什么在Redux中推荐使用不可变更新方式的原因之一——确保对象引用变化能被Reselect检测到。
内容的提问来源于stack exchange,提问作者Natsuo
相关产品推荐
相关产品推荐

