React性能优化——代码篇
来源:互联网 发布:程序员和设计师 编辑:程序博客网 时间:2024/06/05 10:26
如果使用工具检测出页面浪费的渲染次数太多,就需要检查代码是否写法上有问题了。虽然 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 = falseonMouseDown = () => {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
没有成为性能瓶颈之前,这都只是代码写法上的事。
- React性能优化——代码篇
- React性能优化——代码篇
- React性能优化——工具篇
- React性能优化——工具篇
- Android性能优化——代码优化
- React-性能优化详解
- React Native性能优化
- React组件性能优化
- react性能优化
- react 性能优化工具
- React性能优化总结
- react优化性能
- React性能优化总结
- React Native性能优化
- React Native性能优化
- React 组件性能优化
- Android性能优化的——Java(Android)代码优化
- 系统性能优化总结—java代码优化
- 【U3D】关于 UGUI按钮:Button 以及事件:EventTrigger 的一些经验教训
- 模拟点击
- Java并发修改错误ConcurrentModificationException分析
- 新同学老司机们,说说你的第一次......上云体验!
- HTML5介绍
- React性能优化——代码篇
- centos7下配置nginx+php+mysql
- Longest Word in Dictionary through Deleting问题及解法
- Linux下线程pid和tid
- HessianProtocolException: '' is an unknown code问题解决
- HTML编辑器kindeditor.js开头老是省略空格键
- php中浮点数相关处理(待完善)
- IO流概念
- Java一些基础知识