东莞市盛裕绒艺玩具有限公司

东莞市盛裕绒艺玩具有限公司

乐众游戏最新网站

18577908347
联系方式
全国服务热线: 18577908347

咨询热线:15270866193
联系人:龙生
地址:内蒙古自治省乌海市乌达区胜利西街6号

你所要掌握的最简单基础的React渲染优化

来源:乐众游戏最新网站   发布时间:2019-06-26   点击量:186

一、React的渲染机制

要掌握一两项React-render优化的方法不难,但是非常重要.无论是在实际项目中的一个小细节,还是迎合"面试官"的口味

1.1 触发Render

我们知道React要更新视图,必须要触发Render.而这往往是影响性能最重要的一步(因为操作了dom).而React之所以这么出色,正是因为占其主导地位的diff算法采用了虚拟DOM(React V-dom),使得渲染性能大大提升。

即便如此,我们在开发的时候也应该要注意一些性能的优化,比如避免无意义的render

那么,触发render的条件有哪些呢?

    首次加载组件使用了setState(更新了Props)Props更新了(父级传给子级的值改变了)

我们完全可以避免2.3情况导致的一些性能问题

1.2 React Diff

虽然说React高效的Diff算法完美结合了虚拟DOM,让用户可以"无限制"刷新而不需要考虑任何性能问题.但diff算法还是需要一定的时间,如果你不在意触发render的细节,项目模块大了起来,自然就会影响性能了.

1.3 不做任何优化的例子

我尝试着从实现以下功能:

    不更新state的值,但是调用了setState方法传给子级的值不改变,即子级props实际上是没变化的

// 父级.jsimport React from "react"import MockChild from "./child/index.js"export default class Demo5 extends React.Component{ constructor(args){ super(args) this.state = { "mockNum": 0 } } handleClick(){ this.setState({ "mockNum": 0, }) } render(){ console.log("父级state ==============>", this.state) return( <div> <button onClick={this.handleClick.bind(this)}>点击</button> <MockChild mockNum={this.state.mockNum}/> </div> ) }}//子组件render(){ console.log("子级Props =============>", this.props) return( <div></div> )}

我们反复点击按钮,虽然state的值并没有任何变化,但是我们看打印的结果!

render重复渲染了!

可能会疑问,我在项目并不会做这么一种无用功的!但实际上,当一个组件逻辑复杂起来之后,会产生各种各样的情况.比如:

比如一个组件的中有个包含onChange事件的input,当我改变该输入框内容的时候调用了setState,渲染视图的时候也会触发子组件的重新render.但我们明明没有做任何和子组件有联系的操作例如上面的例子:

//父组件.jsstate = { "mockValue": "123" }handleChange(e){ this.setState({ "value": "123", })}//render<input onChange={this.handleChange.bind(this)} /><MockChild />/** 子组件不做变化*/

很不爽,真的!必须给安排掉.

二、基础的React优化

2.1 生命周期: shouldComponentUpdate

可能没听过shouldComponentUpdate,我们简单介绍一下它的执行周期

不熟悉React生命周期的可以看看这篇文章:《React生命周期执行顺序详解》

可以看到它是在render渲染之前触发的,只要我们在这里加以判断就可以有效阻止"无用"的render触发.当然你说componentWillReceiveProps也可以,当然!但是它只有props的更新判断,而有时候我们也不能放过未更改的state!

shouldComponentUpdate(nextProps, nextState){ if(nextState !== this.state && nextProps !== this.props) return true; return false}

这么简短的代码就可以解决冗余的render触发.当然有时候项目规模大了之后,就需要具体到某一个值

nextState.xxx !== this.state.xxx && ...

2.2 PureComponent

先介绍PureComponent的用法,实在是太简便了

import React, { PureComponent } from "react"export default class Demo5 extends PureComponent{}

实际上就是把React.Component代替成PureComponent.

可能会疑问那PureComponent应该是一个插件吧?为什么就在react包里?其实它是官方在React15.3提出的一个"纯净的组件"

在版本允许的情况下,还是建议使用PureComponent,既能优化render次数,也能减少shouldComponentUpdate的代码。但是PureComponent只是执行了浅比较

什么是浅比较呢?

我们先来看看源码

if (this._compositeType === CompositeTypes.PureClass) { shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState);}

可以看到判断主要是通过shallowEqual方法执行的(即可以判断state,也可以判断props)

shallowEqual具体作用是什么呢?实际上它使用了ES6的Object.keys.只是做了以下这么几个判断:

    新的和旧的props(state)是否两者都有相同的key?引用是否改变

第二种可能有点难以理解,什么是引用是否改变?

简单地解释就是,是否有新的元素参与改变

举个官方常用例子:

class App extends PureComponent { state = { items: [1, 2, 3] } handleClick = () => { const { items } = this.state; items.pop(); this.setState({ items }); } render() { return (<div> <ul> {this.state.items.map(i => <li key={i}>{i}</li>)} </ul> <button onClick={this.handleClick}>delete</button> </div>) }}

可以看到,我们点击delete的时候,虽然items数组执行了pop()方法,删除最后一项!但是li标签却没变少!那是因为shallowEqual根本不吃你这套.它认为items还是同一个引用,所以给我true!在通过!反过来就是false

那要如果改变引用呢?我们可以这样尝试.(这也是解决浅比较常用的一个办法)

this.setState({ items: [].concat(items) });

当然,大多数情况我们都可以通过PureComponent解决啦!实在不行,还可以通过componentWillReceiveProps进一步判断呢!

PureComponent更多的介绍可以看:《React PureComponent 使用指南》

相关产品

COPYRIGHTS©2017 乐众游戏最新网站 ALL RIGHTS RESERVED 备案号:186