美文网首页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