Redux - 了解返回函数的高级mapStateToProps

iQ.*_*iQ. 6 javascript reactjs redux react-redux

我试图在返回函数时理解mapStateToProps的机制.

所以我找不到很多文档,除了Redux文档的一个简短的摘录,通过返回一个函数提前说明,每个实例将获得自己的memoized mapStateToProps,另一个用户说这是一个优化,阻止mapStateToProps被调用父母道具变化.

所以对于列表项来说这看起来很棒,我不想为任何不影响项目的更改重新呈现大项目列表.

所以令我困惑的部分是,不会为任何父道具更改调用mapStateToProps,这是否意味着为了重新呈现单个列表'Item',它需要是一个智能连接组件才能获取改变它关心并重新渲染?或者这是否意味着它永远不会为这个特定的Item实例重新渲染?

更新:

想要澄清一下,我正在具体谈论mapStateProps的工厂功能版本.

以下是我所讨论的功能,取自React-Redux文档:

注意:在需要更多控制渲染性能的高级场景中,mapStateToProps()也可以返回一个函数.在这种情况下,该函数将用作特定组件实例的mapStateToProps().这允许您进行每个实例的memoization.您可以参考#279及其添加的测试以获取更多详细信息.大多数应用从不需要这个.

和本文中的段落:

https://medium.com/@cvetanov/redux-mapstatetoprops-optimization-5880078a8a7a

如果redux接收到一个返回函数的实现,它会执行一个闭包来包装组件自己的props,因此每次组件更改它从父组件接收的props时,都会绕过mapStateToProps的调用.它创建了一个所谓的purePropsSelector.如何做到这一点可以在这里看到.

更新2:

我正在调查提到跳过的文章,它似乎是当你在一个闭包中包装自己的道具并返回一个只使用状态的函数.因此,当父内容为每个"已连接"子项更改时,它会阻止调用mapStateToProps.

这取自我上面读到的那篇中篇文章:

function mapStateToPropsFactory(initialState, ownProps) {
  // a closure for ownProps is created
  // this factory is not invoked everytime the component
  // changes it's props
  return function mapStateToProps(state) {
    return {
      blogs:
        state.blogs.filter(blog => blog.author === ownProps.user)
    };
  };
}
export default connect(mapStateToPropsFactory)(MyBlogs);
Run Code Online (Sandbox Code Playgroud)

tri*_*ixn 9

mapStateToProps如果状态改变,将始终调用每个函数.redux中没有包含防止mapStateToProps被调用的机制.

来自以下文档connect():

mapStateToProps(state, [ownProps]): stateProps] (Function):如果指定了此参数,则新组件将订阅Redux存储更新.这意味着每次更新商店时,都会调用mapStateToProps.

你想要阻止的东西(通常是使用选择器)是内部发生的昂贵计算mapStateToProps将在每次状态更新时重复,即使它们产生相同的结果.

或者这是否意味着它永远不会为这个特定的Item实例重新渲染?

如果连接组件收到的任何道具发生变化,它将照常重新渲染.关键是要防止mapStateToProps进行昂贵的计算.mapStateToProps愚蠢.它进行计算并将它们作为道具传递给连接的组件.然后该组件检查道具是否与之前的道具不同,并决定基于此重新渲染.

考虑mapStateToProps使用选择器的这个函数getVisibleTodos:

const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}
Run Code Online (Sandbox Code Playgroud)

选择器记住调用的结果,只要输入参数没有改变,它就会在后续调用中返回该结果.此示例中的选择器仅从redux状态获取其输入.只要state.todosstate.visibilityFilter不改变它就可以使用上次调用的记忆结果,而不需要重新计算某些东西.

现在考虑另一个例子:

const TodoList = ({id, todos}) => (
  <ul id={id}>
    {todos.map(/* ... */)}
  </ul>
);

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

export default connect(mapStateToProps)(TodoList);
Run Code Online (Sandbox Code Playgroud)

这次选择器还将组件自己的道具作为输入.这是有问题的,因为如果我们使用两个连接的实例TodoList并渲染它

<TodoList id="list1" />
<TodoList id="list2" />
Run Code Online (Sandbox Code Playgroud)

这将导致mapStateToProps在状态更新时调用两次,每个TodoList实例一次.两次它都会收到不同的道具.一次{id: 'list1'}和第二次一起{id: 'list2'}.但两个组件共享相同的选择器.即使todos每个人都TodoList没有改变,这也会导致选择器重新计算.现在mapStateToProps返回函数的函数发挥作用:

const makeMapStateToProps = () => {
  const getVisibleTodos = makeGetVisibleTodos() // this creates a new selector function
  const mapStateToProps = (state, props) => {
    return {
      todos: getVisibleTodos(state, props)
    }
  }
  return mapStateToProps
}
Run Code Online (Sandbox Code Playgroud)

mapStateToProps为每个实例创建了一个单独的函数,TodoList它有自己的选择器,这样它就可以单独记住每个实例的props,并且只会重新计算它为创建它的实例的props是否有变化.这将解决前一个示例中的问题.

所以tl; dr;:当内部选择器mapStateToProps将连接组件的自己的道具作为参数时,您需要使用mapStateToProps工厂作为工厂来实现每个实例的记忆.

您可以在redux文档中的Comuting Derived Data下的示例中找到更详细的说明.