由列表优化谈起re-render
why re-render?
这两天在看项目的渲染优化题,决定总结一下,发现不论是代码写法和组件规划以及列表之间的交互,都是有可能会引起性能问题的罪魁祸首。
首先分析一下,组件何时更新?为何更新?
how does React decide to re-render a component
component state change
举个栗子:
class Test extends React.Component { constructor(props) { super(props) this.state = { value: 0 } } handleClick = () => { this.setState({ value: this.state.value ++ }) } render() { return (<div onClick={this.handleClick}>{this.state.text}</div>) } }
但是大家都知道,react的实现思想就是virtual DOM,每次state的改变都会引起re-render,不管state里的值是否真正用到了组件中,我从一遍博客中看到这样的描述:A re-render can only be triggered if a component’s state has changed. The state can change from a
props
change, or from a directsetState
change. The component gets the updated state and React decides if it should re-render the component. Unfortunately, by default React is incredibly simplistic and basically re-renders everything all the time.那么什么东西适合放在state里----需要持续维护的一个局部状态或者跟UI相关的状态才去放在state里,而那些只是暂时性的东西或者特定函数里才会用到的,只需要放在组件实例中。最后一句话:state虽灵活,用时需谨慎。component props change
先放栗子:
class Mine extends React.Component { render() { const { childIds } = this.props return ( <FileLis childIds={childIds} /> ) } } export default connect((state, ownProps) => { childIds: selectFileChildIds(state, ownProps.match.params.guid || '0') })(Mine)
很简单,当数据改变的时候必然会re-render
react component re-render in these instances
Parent component re-render
Calling this.setState() within the component 并且会依次根据react 生命周期更新 shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate
component's props changes. 并且依次走生命周期 componentWillReceivePorps -> shouldComponentUpdate -> componentWillUpdate -> render -> componentDidUpdate(connect method of react-redux trigger this when there are applicable changes in the Redux store)
calling this.forceUpdate which is similar to this.setState
Re-render necessary or unnecessarily?
什么是必须的re-render什么是不必要的re-render,我们可以借助react-devtools,勾选Highlight Updates,
然后click button or do some thing 引起组件的render,这里有个todo list highlight-demo.firebaseapp.com/你会看到页面上会出现蓝色,绿色, 黄色,红色。其中蓝色是指最不频繁的更新,其次是绿色,黄色,红色。黄色和红色并不一定是不好的,之所以出现黄色或者红色,组件这个时候确实因为某些state或者props改变导致了频繁更新。
比如项目中桌面列表的渲染:
只是简单的修改了某个文件的一个属性,会看到整个list都重绘了一遍,设置右边和左边的侧栏以及header都re-render了,这就是不必要的re-render
优化列表以后的效果:
可以看到绿色部分只是修改的file发生了re-render
why did you updated
在优化列表渲染的时候,用到了一个辅助工具--why-did-you-update
既然列表在重复渲染,那就要知道到底哪个组件哪个东西引起了重复渲染,其实我们是有线索可以查找的,然后借助why-did-you-update这个工具会帮助我们在控制台显示哪些组件在重复渲染,以及什么原因导致的。
Why-did-you-update 是个npm 包,npm install --save why-did-you-update or yarn add --save why-did-update
开发环境下使用它
import Rect from 'react'
if (process.env.NODE_ENV !== 'production') {
const { whyDidYouUpdate } = require('why-did-you-update')
whyDIdYouUpdate(React)
}
分析结果
减少或者控制不必要的re-render
use PureComponent
合理使用props传递数据
计算放在connect里
尽量不要传递state
不要在react component render 里使用箭头函数
class Item extends React.Component {
render() {
const { mode } = this.props
return (
<div onCick={() => this.handleClick(mode)}>...</div>
)
}
}
👆的做法每次render都会生成一个新的匿名函数,然而其实函数并没有变只是引用变了,造成re-render。The problem with using an arrow function in the render call is it will create a new function every time, which ends up causing unneeded re-renders
参考资料
stackoverflow.com/questions/4…