博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
React性能优化 -- 利用React-Redux
阅读量:6316 次
发布时间:2019-06-22

本文共 3156 字,大约阅读时间需要 10 分钟。

React渲染机制

前面这篇,我已经介绍了React的渲染机制.

简单来说,就是在页面一开始打开的时候,React会调用render函数构建一棵Dom树,在state/props发生改变的时候,render函数会被再次调用渲染出另外一棵virtula Dom,接着,React会用对两棵树进行对比,计算出对DOM树的最少修改,然后批量改动。

找出优化点

注意这里面,如果可以在渲染virtual DOM之前就可以判断渲染结果不会有变化,那么可以直接不进行virtual DOM的渲染和比较,速度回更快。

shouldComponentUpdate

怎么可以做到呢?

这里需要用到React生命周期里的shouldComponentUpdate,当这个函数返回false的时候,DOM tree直接不需要重新渲染,从而节省大量的计算资源。

由于每个React组件的逻辑都有自己的特点,所以需要根据组件逻辑来定制shouldComponentUpdate函数的行为.

以官网的TodoList为例:

import React, { Component, PropTypes } from 'react'export default class Todo extends Component {  render() {    return (      
  • {this.props.text}
  • ) }}Todo.propTypes = { onClick: PropTypes.func.isRequired, text: PropTypes.string.isRequired, completed: PropTypes.bool.isRequired}

    对于这个todo来说,只要completed跟text都没有发生改变,那么这个组件渲染的结果就不会发生改变,因此,shouldComponentUpdate就可以这样写:

    shouleComponentUpdate(nextProps, nextState) {  return (nextProps.completed !== this.props.completed) ||          (nextProps.text !== this.props.text)}

    两个问题

    接下来就有两个问题需要我们思考了:

    1. 是不是所有的组件都需要这个shouldComponentUpdate
    2. 每个需要shouldComponentUpdate的组件都需要自己写逻辑是不是太麻烦了

    问题一:

    关于这个问题,我在前一篇其实已经作答,使用React Pref,或者why-did-you-update都可以找到无需被重新渲染的组件,这个组件就是需要使用shouldComponetUpdate优化的组件。

    问题二:

    确实麻烦啊,能偷懒就偷懒的我们怎么能忍受。

    所以可以直接使用React-Redux的帮助我们.

    React-Redux的connect其实会自动做一个对props的优化比较。过程如下:

    clipboard.png

    简而言之,它会根据传入进来的props,state通过各种计算得到nextProps跟上一个props做比较,如果不相等,shouldComponentUpdate才会返回false。

    所以,有了它,todo.js就可以这样写

    import React, { Component, PropTypes } from 'react'class Todo extends Component {  render() {    return (      
  • {this.props.text}
  • ) }}Todo.propTypes = { onClick: PropTypes.func.isRequired, text: PropTypes.string.isRequired, completed: PropTypes.bool.isRequired}export default connect()(Todo);

    跟踪问题

    这里我使用React Pref跟踪问题,加上之后,查看控制台,可以看到浪费的渲染时间由TodoList -> Todo转变到了Connect(Todo)> Todo,要理解这个现象就要理解connect里shouldComponentUpdate的实现方式。

    注意:

    clipboard.png

    这里对props的对比只是一个浅比较,所以要让react-redux认为前后的对象是相同的,必须指向同一个js对象。

    例如:

    这样每次传入进来的style都是一个新的对象,所以即使里面的值相等,react-redux的浅比较仍然认为它不等需要重新渲染。

    再回来看看TodoList里是怎么用Todo的

      {this.props.todos.map((todo, index) =>
      this.props.onTodoClick(index)} /> )}

    不知道大家发现了没有?这里的每一个onClick都是一个新的函数,即使Todo被装备了shouldComponentUpdate的实现,浅比较的时候props总是不相等,依旧躲不过每次更新都要被重新渲染的命运。

    如何改进

    有两种做法:

    方法一:

    先来看看这个onTodoClick是怎么被一层层传下来的:

    // App.js
    dispatch(toggleTodo(index))}/>// TodoList.js
    this.props.onTodoClick(index)}/>//todo.js
  • {this.props.text}
  • 可以在TodoList的时候,不构造匿名函数直接将onTodoClick传下来,然后index可以放在新加的属性index里。

    // TodoList.js 
    //todo.js的mapDispatchToProps需要做对应的改变const mapDispatchToProps = (dispatch, ownProps) => ({ onClick: () => ownProps.onToggle(ownProps.id)})

    方法二:

    直接让TodoList不要给todo传递任何函数类型的prop,点击事件完全由todo组件自己搞定。

    // TodoList只需要穿一个id出来 
    // todo中,自己通过react-redux派发action即可const mapDispatchToProps = (dispatch, ownProps) => { const {id} = this.props; return { onClick: () => dispatch(toggleTodo(id)) }}

    对比两种方式,其实对于todo来说,都需要使用react-redux,都需要todoList传入一个id,区别只在于actions是由父组件还是有组件自己导入。

    相比而言,没有必要一层层传递这个action,第二种方式让todo处理自己的一切事务,更符合高内聚的要求。

    总结

    讲了那么多,总之就是通过React Pref帮我们找到需要优化的组件,然后用connect帮助我们做优化偷个懒。

    参考:

    <深入浅出React和Redux> -- 程墨

    转载地址:http://vfuaa.baihongyu.com/

    你可能感兴趣的文章
    10种阻碍程序员职业生涯发展的行为
    查看>>
    MySQL 触发器简单实例
    查看>>
    一本介绍C指针的书--指针是什么1.1
    查看>>
    File Formats in Big Data Platform
    查看>>
    request获得所有参数
    查看>>
    编程原则
    查看>>
    Hystrix降级逻辑中如何获取触发的异常
    查看>>
    [日推荐] 『KORJO母爱小空间』妈妈带宝宝出门再也不用愁啦!
    查看>>
    【微信小程序经验】各类图表相关组件+Demo源码(折线图,柱状图,K线,分时图)...
    查看>>
    查询约束关联的表
    查看>>
    阻止Adobe Dreamweaver CS5官方序列号验证
    查看>>
    maven的pom文件各节点的功能介绍
    查看>>
    Adobe Acrobat DC怎样删一部分页面
    查看>>
    python编码知识
    查看>>
    极光大数据告诉你,程序员们都在"愁"些啥?
    查看>>
    boostrapv3学习笔记
    查看>>
    python3
    查看>>
    android 设计的优点
    查看>>
    android adb
    查看>>
    json格式化
    查看>>