React性能优化——代码篇
2017-10-08 08:30
253 查看
如果使用工具检测出页面浪费的渲染次数太多,就需要检查代码是否写法上有问题了。虽然
转载https://wulv.site/2017-07-02/react-perf-code.html
如果
在
比如我们确定如果一个子组件的
我们最好只传递
PureComponent 使用指南。
我们可以将确定不变的
这个操作其实有
如果是和视图无关的,但有变化的数据,不要放在
总结一下:
在
如果每次都在
关于
Will
Function.prototype.bind() always be slow?
Why
is bind slower than a closure?
总的来说,目前浏览器已经足够快了,在
Virtual DOM算法可以避免大多无效的真实
DOM操作,但还是会浪费时间在计算不会改变的虚拟
DOM上,也就是执行了
render函数,但发现并没有任何改变。
转载https://wulv.site/2017-07-02/react-perf-code.html
key
key属性作为列表的子组件的身份标识,是不能重复的。不写
key属性,
React会在浏览器控制台报
warning,有时候我们为了去除这个警告,直接使用数组的索引做
key,这是不太好的。
123456789 | class App extends Component { render() { return (<div> {this.props.list.map((value, index) => { <Child key={index} data={value} /> })} </div>); }} |
list发生变化,比如从中间去除一条数据,两次渲染之间
key相同的子组件,
React认为他们是同一个组件,这样很多个
Child组件都改变了。最好使用一个唯一的
value.id,如果没有
id,使用
value.name之类的也是可以的,
key不必须是数字,只要保证不重复的字符就可以了。
shouldComponentUpdate
在 React生命周期里,
shouldComponentUpdate表示组件是否需要被更新,我们可以做一些判断,来优化组件性能,让一些确定不会改变视图的操作,直接不去计算。
shouldComponentUpdate在初始化时或者使用
forceUpdate时是不被执行的。
shouldComponentUpdate默认返回值是
true,也就是组件一定会更新,如果返回值为
false,会阻止后面
componentWillUpdate、
render、
componentDidUpdate等操作。并且如果
componentWillReceiveProps里有
setState操作也会被阻止。
比如我们确定如果一个子组件的
name和
tel属性不变,子组件就不需要更新:
1234567 | shouldComponentUpdate(nextProps) { const { data } = this.props; const { name, tel } = data; return name !== nextProps.data.name || tel !== nextProps.data.tel;} |
component需要的
props,如果传得太多,或者层次传得太深,都会加重
shouldComponentUpdate里面的数据比较负担,因此,也请慎用
<Component {...this.props} />操作。
123456789 | import pick from 'lodash/pick';class App extends Component { const props = pick(this.props, [max, min, onClick]) render() { return (<div> <NumberInput {...props} /> </div>); }} |
PureComponent
PureComponent是一个很有效的优化,在前面的博客专门有一篇来介绍:React
PureComponent 使用指南。
Stateless
components
React v0.14就添加了
functional components,他的行为很像只有一个
render方法的
class components,但没有生命周期方法,也没有实例对象,所以不能够使用
ref。目前来说
functional components并没有特别优化,在内部也是包装在同一个类中。我们可以直接以函数方式使用,这样可以优化一部分性能:
12345678910111213 | const Avatar = (props) => { return <img src={props.url} />;}// 组件方式使用render() { return (<div> <Avatar url={avatarUrl} /> </div>);// 函数方式使用render() { return (<div> {Avatar({ url: avatarUrl })} </div>); |
React官方已经承诺,在未来会通过避免不必要的检查和内存分配来对这些组件进行性能优化。
constant
elements
我们可以将确定不变的html代码抽离出来直接当做一个变量,写在
jsx里,会解析
jsx语法,生成
React.createElement()代码。如果提升成静态元素,
jsx会直接把它们当做一个值,减少了解析过程:
1234567891011 | const _ref = <span>Hello World</span>;class MyComponent extends Component { render() { return ( <div className={this.props.className}> {_ref} </div> ); }} |
babel插件babel-react-optimize,可以自动帮我们提取。
慎用setState
如果是和视图无关的,但有变化的数据,不要放在 state里面,比如某个组件需要
mouseDown时标记开始记录,
mouseUp清除记录,最好直接当做实例的一个属性。这样可以避免执行无效的
render操作。
1234567891011121314 | class App extends Component { record = false onMouseDown = () => { this.record = true; } onMouseUp = () => { this.record = false; } render() { return (<div> <button onMouseDown={this.onMouseDown} onMouseUp={this.onMouseUp} /> <div/>); }} |
render函数里面要用到的东西放
props/state(影响
view),其他的不要放进去,写成模块内的私有变量(跨实例共享)或者组件实例上的变量。
在
React PureComponent使用指南里,复杂状态与简单状态不要共用一个组件那一段也提到了慎用
setState的原因。
慎用bind
Component的
render里不使用
bind绑定
this,可以放在
constructor里绑定好,或者直接使用箭头函数,如果要动态传参,可以使用闭包,或者可以直接把处理函数传入子组件,子组建时可以拿到参数,再执行父组件的处理函数就可以了。
1234567891011121314151617181920212223242526272829303132333435363738394041 | // 闭包class App extends Component { removeCharacter = index => () => { const { list } = this.state; list.splice(index, 1); this.setState({ list }); } render() { return (<div> {this.state.list.map((value, index) => <Child onClick={this.removeCharacter(index)} key={value.id} data={value} /> )} </div>); }}// 子组件处理class App extends Component { removeCharacter = index => { const { list } = this.state; list.splice(index, 1); this.setState({ list }); } render() { return (<div> {this.state.list.map((value, index) => <Child onClick={this.removeCharacter} index={index} key={value.id} data={value} /> )} </div>); }}class Child extends Component { handleClick = () => { const { index, onClick } =this.props; onClick(index); } render() { return <div onClick={this.handleClick}> {this.props.data} </div> }} |
render里面的
jsx去
bind这个方法,会消耗性能,因为每次
bind都会返回一个新函数,重复创建静态函数肯定是不合适的(闭包也是这样,但
bind内部有一系列的算法,比闭包复杂多了)。
关于
bind性能问题可以查看以下资料:
Will
Function.prototype.bind() always be slow?
Why
is bind slower than a closure?
总的来说,目前浏览器已经足够快了,在
bind没有成为性能瓶颈之前,这都只是代码写法上的事。
相关文章推荐
- 35 个 Java 代码性能优化总结(一)
- Trinea性能优化之Android代码优化
- Java开发代码性能优化
- 性能优化之Java(Android)代码优化
- Python 代码性能优化技巧
- Java代码性能优化总结
- 从数据库、代码和服务器对PHP网站Mysql做性能优化
- [转]Python 代码性能优化技巧
- java性能优化:35个小细节让你提升java代码的运行效率
- 35 个 Java 代码性能优化总结
- 35 个 Java 代码性能优化总结
- 性能优化第三篇---Java(Android)代码优化
- 35 个 Java 代码性能优化总结
- dispatch_once优化代码性能
- 笔记45 | 代码性能优化建议[转]
- 不修改代码就能优化ASP.NET网站性能的一些方法
- (4.6.4)性能优化之Java(Android)代码优化
- 关于代码性能优化的几点建议
- 35 个 Java 代码性能优化总结
- 月薪上万做好这一步:程序员职场中必须掌握的的Java代码性能优化技巧