Redux Reselect备忘录如何工作?

时间:2018-10-02 11:35:36

标签: reactjs redux react-redux reselect

我正在尝试将reselect集成到当前版本中,并且一如既往,首先我开始阅读文档,然后如果需要的话,又重新整理了文档。我无法理解文档的一个特殊部分,也不能找不到可以用更清晰的方式解释的资源。现在我在这里得到一些明确的解释。 因此它在文档`

中说
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>
)
  

将getVisibleTodos选择器与   VisibleTodoList容器将无法正确记住:

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
  

使用createSelector创建的选择器的缓存大小为1,并且仅   当其参数集与它的参数相同时,返回缓存的值   前一组参数。如果我们在渲染之间交替   <VisibleTodoList listId="1" /><VisibleTodoList listId="2" />,   共享选择器将在接收{listId: 1}和   {listId: 2}作为它的props参数。这将导致参数为   每次调用都不同,因此选择器将始终重新计算   返回缓存值的方法。

注意最后一句话。如果我们传递不同的id并返回不同的值,为什么要返回缓存的值取决于id呢?

2 个答案:

答案 0 :(得分:3)

所以我们有这个选择器来获取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参数,因此它只返回记录的值。

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

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

  2. 选择器第二次被调用,它发现{ listId: 2 }与第一次{ listId: 1 }的道具参数不同,因此它重新计算并记住新结果(待办事项列表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. 使用<VisibleTodoList listId="1" />调用选择器的第一个实例,并记录结果

  2. 使用<VisibleTodoList listId="2" />调用选择器的另一个实例,并记录结果

答案 1 :(得分:0)

否,它不会返回错误的值。文档只是说备忘录在这种情况下根本不起作用。要使其工作(意思是“节省一些资源并避免重复相同的计算”),就需要。

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

  

我们将在下一节中了解如何克服此限制。

next section Sharing Selectors with Props Across Multiple Component Instances

  

要在多个VisibleTodoList实例之间共享选择器,同时传递道具并保留备忘录,组件的每个实例都需要自己的选择器私有副本。

还可以确保将备注大小增加到大于1。