Redux Reselect 记忆化是如何工作的?

How does Redux Reselect memoization work?

我正在尝试将 reselect 集成到我当前的应用程序中,一如既往,我首先开始阅读文档,然后如果需要,另一个 recources.I 无法理解文档的一个特殊部分而且也找不到可以更清楚地解释的资源 way.Now 我来这里是为了得到一些明确的解释。 所以它在文档中说`

import React from 'react'
import Footer from './Footer'
import AddTodo from '../containers/AddTodo'
import VisibleTodoList from '../containers/VisibleTodoList'

const App = () => (
  <div>
    <VisibleTodoList listId="1" />
    <VisibleTodoList listId="2" />
    <VisibleTodoList listId="3" />
  </div>
)

Using the getVisibleTodos selector with multiple instances of the VisibleTodoList container will not correctly memoize:

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
import { getVisibleTodos } from '../selectors'

const mapStateToProps = (state, props) => {
  return {
    // WARNING: THE FOLLOWING SELECTOR DOES NOT CORRECTLY MEMOIZE
    todos: getVisibleTodos(state, props)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

A selector created with createSelector has a cache size of 1 and only returns the cached value when its set of arguments is the same as its previous set of arguments. If we alternate between rendering <VisibleTodoList listId="1" /> and <VisibleTodoList listId="2" />, the shared selector will alternate between receiving {listId: 1} and {listId: 2} as its props argument. This will cause the arguments to be different on each call, so the selector will always recompute instead of returning the cached value.

注意最后一句话。如果我们传递不同的 ids 为什么要 return 缓存值并且它应该 return 我们不同的值取决于 ids ?

不,它没有 return 错误的值。文档只是说记忆对于这种情况根本不起作用。要让它工作(意思是 "save some resources and avoid repeating the same calculation"),你需要。

实际上文档说(您引用的部分中的最后一句话):

We’ll see how to overcome this limitation in the next section.

并且next section Sharing Selectors with Props Across Multiple Component Instances

To share a selector across multiple VisibleTodoList instances while passing in props and retaining memoization, each instance of the component needs its own private copy of the selector.

当然你也可以将 memoization 大小增加到 1 以上。

所以我们让这个选择器为我们的 VisibleTodoList 组件获取状态:

const mapStateToProps = (state, props) => {
  return {
    todos: getVisibleTodos(state, props)
  }
}

如果我们渲染组件:

return (
    <div>
        <VisibleTodoList listId="1" />
    </div>
)

然后,选择器被调用为:getVisibleTodos(state, { listId: 1 }),选择器将结果(待办事项列表 1 对象)存储(记忆)在内存中。

如果我们使用相同的道具渲染组件两次:

return (
    <div>
        <VisibleTodoList listId="1" />
        <VisibleTodoList listId="1" />
    </div>
)
  1. 选择器被调用并且结果被记忆

  2. 选择器第二次被调用,它看到 { listId: 1 } 是与第一次相同的 prop 参数,所以它只是 returns 记忆值。

如果我们用不同的 props 渲染组件两次:

return (
    <div>
        <VisibleTodoList listId="1" />
        <VisibleTodoList listId="2" />
    </div>
)
  1. 选择器被调用并且结果被记忆

  2. 选择器第二次被调用,它发现 { listId: 2 } 与第一次 { listId: 1 } 的 props args 不同,所以它重新计算并记住新的结果(待办事项列表 2 对象)在内存中(覆盖之前的记忆)。

如果我们希望每个组件都有自己的记忆,每个组件实例必须有自己的选择器实例。

例如:

// selector
const makeGetVisibleTodos = () => createSelector(
    // ... get the visible todos
);

// each has their own memoization space:
const foo = makeGetVisibleTodos(); // this is an instance
const bar = makeGetVisibleTodos(); // this is a separate instance

因此将其应用于组件:

// component
const mapStateToProps = () => {
    const getVisibleTodos = makeGetVisibleTodos(); // this instance get bound to the component instance

    return (state, props) => {
        return {
            todos: getVisibleTodos(state, props)
        }   
    }
}

现在,如果我们用不同的道具渲染组件两次:

return (
    <div>
        <VisibleTodoList listId="1" />
        <VisibleTodoList listId="2" />
    </div>
)
  1. with <VisibleTodoList listId="1" /> 选择器的第一个实例被调用并且结果被记忆

  2. <VisibleTodoList listId="2" /> 不同的选择器实例被调用并且结果被记忆