React性能探索 --- 避免不必要渲染
背景上一篇文章的结尾 本篇文章来具体解答这个问题。 应用分析首先,先看这个应用:页面的两部分分别渲染5000个节点,从1-5000。当点击按钮之后,第二部分的节点会更新,重新渲染从2-5001的数字,但是第一部分保持不变。 import React,{ createElement,Component } from 'react'; import {render} from 'react-dom'; import Perf from 'react-addons-perf'; import ListItem from './ListItem' function arrayGenerator(length) { return Array.apply(null,{ length: length }).map(Number.call,Number) } class App extends Component { constructor(props) { super(props) this.state = { multiplier: 1 } } resetMultiplier() { this.setState({ multiplier: 2 }) } render() { return ( <div className="App"> <button onClick={this.resetMultiplier.bind(this)}>Click Me</button> <ul> { arrayGenerator(5000).map(i => { return <ListItem key={i} text={i}/> }) } { arrayGenerator(5000).map(i => { return <ListItem key={i} text={i + this.state.multiplier}/> }) } </ul> </div> ); } } render(<App />,document.getElementById('main')); gitbug 链接: 感兴趣的同学可以下载跑一跑代码 分析更新时间这里用react的Perf工具来测量重新渲染的时间。 使用方法: npm install --save-dev react-addons-perf import Perf from 'react-addons-perf' 这里主要用到四个方法:
当我们点击按钮,可以看到控制台打印出下面的信息:
由控制台的数据可以看出,App用了90.59ms渲染,其中渲染ListItem的时间为55ms,渲染了10000次,其中有5000次是浪费的,因为这部分页面的内容完全没有更新的改动。 如何修复既然是不需要渲染,那就要阻止它的渲染。React给我们提供了一个方法shouldComponentUpdate(),当这个方法返回true的时候,需要重新渲染,false的时候不需要(默认是true). 在这个栗子中,只要text的值不变,就不需要重新渲染。所以,可以这样改写ListItem 的shouldComponentUpdate import React,{ Component } from 'react' export default class ListItem extends Component { shouldComponentUpdate(nextProps,nextState) { return nextProps.text !== this.props.text } render() { let { text } = this.props return <li>{text}</li> } } 在重新点击一下按钮,在控制台可以发现
App总的渲染时间降到了62.14ms,并且ListItem只重新渲染了5000个节点,完全消除了浪费的渲染。 对于上面的写法,React提供了一个新的组件PureComponent来做这件事,它会自动浅对比props/state,当两者相同的时候不渲染节点。所以,listItem又可以改写成 import React,{ PureComponent } from 'react' export default class ListItem extends PureComponent { render() { let { text } = this.props return <li>{text}</li> } } 跑一跑代码 通过控制台可以看到达到的效果是一样的(有点误差是正常的)。 这里再安利一个可以发现应用里是否存在不该重新渲染的节点工具:why-did-you-update 使用方法1、npm i --save-dev why-did-you-update 2、 import React from 'react' if (process.env.NODE_ENV !== 'production') { const {whyDidYouUpdate} = require('why-did-you-update') whyDidYouUpdate(React) } 然后点击按钮看控制台
注意的点PureComponent只会浅比较,所以不适合用于深层嵌套的对象。同时,PureComponent不仅仅会跳过自己的重新渲染,还会跳过它所有子节点的,所以要注意,用它的时候是最好没有子节点并且不依赖于global state的展示型组件。 与Staleless的关系不知道有没有人跟我有这样的疑问,无状态组件跟纯净组件有什么不同?这里做一个区分: 无状态组件只是作为一个展示组件,它的好处是:
坏处:
关于如何在实际中使用这两个组件,还要根据具体的实际情况来选择~ 总结综上可以看出,减少不必要的重新渲染对于提升我们的性能有很大的意义。我个人觉得,在实际中,用Perf跟why-did-you-update两个工具已经可以很好帮我们判断哪部分不需要重新渲染,帮助我们做出优化。 遗留点PureComponent那么好用,但是使用PureComponent是有条件的呀~ 由于PureComponent只是做了一个浅比较,所以深层嵌套的对象跟数组都是比不出来的,可能会导致需要渲染的地方没有重新渲染的错误展示。 那么浅比较又是什么呢?下篇文章我们来继续探索 参考链接: 1、https://60devs.com/pure-compo... 2、https://engineering.musefind.... (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |