美文网首页React Native开发让前端飞React Native开发经验集
【吃下这份安利】用reselect提高数据获取性能

【吃下这份安利】用reselect提高数据获取性能

作者: mytac | 来源:发表于2019-01-01 13:20 被阅读24次

    新年第一天,祝大家新年快乐~~为了更好的阅读体验,你可以点击这里查看github原文

    前言

    我从《深入浅出react和redux》中了解到reselect,发现它是redux官方社区的一个选择器库(selector library),这里的“选择器”不是指css中的选择器,他的这个概念是出自nuclear-js

    选择器可以计算派生数据,允许redux存储最小的状态;他是可以组合的,可以用作其他选择器的输入;它也是有效的,不会被重复计算,除非它的参数真的改变了。

    为什么需要reselect

    当你在更新state tree的时候,操作他的reducer就会运行一次;这也就意味着如果你的state tree嵌套很深或是非常庞大,就会产生昂贵的系统开销,因此会带来性能问题。reselectredux的一个中间件,它会帮助你避免这些重复计算。

    你也不用再为不能直接改变state而烦恼,因为选择器自动会创造一份副本,我们只需定义函数,将state直接传入就好。

    使用

    import { createSelector } from 'reselect'
    
    const getVisibilityFilter = (state) => state.visibilityFilter
    const getTodos = (state) => state.todos
    
    export const getVisibleTodos = createSelector(
      [ getVisibilityFilter, getTodos ],
      (visibilityFilter, todos) => {
        switch (visibilityFilter) {
          case 'SHOW_ALL':
            return todos
          case 'SHOW_COMPLETED':
            return todos.filter(t => t.completed)
          case 'SHOW_ACTIVE':
            return todos.filter(t => !t.completed)
        }
      }
    )
    

    在上面的例子中getVisibilityFiltergetTodos两个选择函数不会缓存选择的数据(non-memozied),但使用createSelectorgetVisibleTodos转换为可缓存的选择器(memoized)。

    将选择器与redux store连接

    需要在mapStateToProps中调用选择器,在此例中是上文的getVisibleTodos

    const mapStateToProps = (state) => {
      return {
        todos: getVisibleTodos(state)
      }
    }
    const VisibleTodoList = connect(
      mapStateToProps,
      mapDispatchToProps
    )(TodoList)
    
    export default VisibleTodoList
    

    放在组件中:

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

    如上,在多个组件中,我们的reducer应该根据VisibleTodoList的prop,listId进行数据操作。所以在getTodos中可能会写成:

    const getTodos = (state, props) =>
    state.todoLists[props.listId].todos
    

    props可以从mapStateToProps传递给getVisibleTodos

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

    但是!拥有多个实例的VisibleTodoList不会正确的缓存状态。因为一个选择器只会创建一份缓存,如果我们在两个VisibleTodoList的实例上来回交替,每次的参数都是不一样的,所以选择器会一直重复计算,而不是返回存储好的缓存。

    多个组件共享具有props的选择器

    如果要在传递props和保留缓存状态的同时,使多个VisibleTodoList的实例共享选择器,组件的每个实例都需要他自己的选择器私有副本。让我们创建一个名为makeGetVisibleTodos的函数,每次调用它时都会返回getVisibleTodos选择器的新副本:

    import { createSelector } from 'reselect'
    
    const getVisibilityFilter = (state, props) =>
      state.todoLists[props.listId].visibilityFilter
    
    const getTodos = (state, props) =>
      state.todoLists[props.listId].todos
    
    const makeGetVisibleTodos = () => {
      return createSelector(
        [ getVisibilityFilter, getTodos ],
        (visibilityFilter, todos) => {
          switch (visibilityFilter) {
            case 'SHOW_COMPLETED':
              return todos.filter(todo => todo.completed)
            case 'SHOW_ACTIVE':
              return todos.filter(todo => !todo.completed)
            default:
              return todos
          }
        }
      )
    }
    
    export default makeGetVisibleTodos
    

    先需要调用一次makeGetVisibleTodos,获得getVisibleTodos,在将他传入props中,如下:

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

    参考资料

    1. reselect 官方文档

    最后请大家关注我的订阅号获得更加及时的推送~

    那屋水泡

    相关文章

      网友评论

        本文标题:【吃下这份安利】用reselect提高数据获取性能

        本文链接:https://www.haomeiwen.com/subject/wojnlqtx.html