React Native之组件Component与PureComponent
众所周知,React Native的页面元素是由一个一个的组件所构成的,这些组件包括系统已经提供的组件,如View、TextInput等,还有一些第三方库提供的组件,以及自定义的组件。通常在封装组件的时候都会继承Component,不过在React 15.3版本中系统提供了PureComponent,下面就来看一下这两个组件的区别。
首先声明,PureComponent是Component的一个优化组件,在React中的渲染性能有了大的提升,可以减少不必要的 render操作的次数,从而提高性能。PureComponent 与Component 的生命周期几乎完全相同,但 PureComponent 通过prop和state的浅对比可以有效的减少shouldComponentUpate()被调用的次数。
PureComponent VS Component 原理
当组件更新时,如果组件的props和state都没发生改变,render方法就不会触发,省去 Virtual DOM 的生成和比对过程,达到提升性能的目的。原理就是 React会自动帮我们做了一层浅比较,涉及的函数如下:
if (this._compositeType === CompositeTypes.PureClass) { shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState); }
PureComponent 的shouldComponentUpdate() 只会对对象进行浅对比,如果对象包含复杂的数据结构,它可能会因深层的数据不一致而产生错误的否定判断。所以,在实际使用的时候,当你期望只拥有简单的props和state时,才去继承PureComponent ,或者在你知道深层的数据结构已经发生改变时使用forceUpate() 。
Component
首先要看Component的生命周期示意图。
下面就Component的生命周期
生命周期
getDefaultProps
执行过一次后,被创建的类会有缓存,映射的值会存在this.props,前提是这个prop不是父组件指定的。这个方法在对象被创建之前执行,因此不能在方法内调用this.props ,另外,注意任何getDefaultProps()返回的对象在实例中 共享,而不是复制。
getInitialState
控件加载之前执行,返回值会被用于state的初始化值。
componentWillMount
执行一次,在初始化render之前执行,如果在这个方法内调用setState,render()知道state发生变化,并且只执行一次。
render
调用render()方法时,首先检查this.props和this.state返回一个子元素,子元素可以是DOM组件或者其他自定义复合控件的虚拟实现 。
如果不想渲染可以返回null或者false,这种场景下,React渲染一个<noscript>
标签,当返回null或者false时,ReactDOM.findDOMNode(this)
返回null 。render()方法是很纯净的,这就意味着不要在这个方法里初始化组件的state,每次执行时返回相同的值,不会读写DOM或者与服务器交互,如果必须需要与服务器进行交互,可以在componentDidMount()
方法中实现或者其他生命周期的方法中实现。
componentDidMount
在初始化render之后执行,且只执行一次,在这个方法内,可以访问任何组件,componentDidMount()方法中的子组件需要在父组件之前执行。
shouldComponentUpdate
这个方法在初始化render()时不会执行,当props或者state发生变化时执行,并且是在render之前执行,当新的props或者state不需要更新组件时,返回false。
shouldComponentUpdate: function(nextProps, nextState) { return nextProps.id !== this.props.id; }
当shouldComponentUpdate()
返回false时,render()方法将不会执行,componentWillUpdate()
和componentDidUpdate()
也不会被调用。
默认情况下,shouldComponentUpdate
方法返回true,防止state快速变化时的问题,但是如果state不变,props只读,可以直接覆盖shouldComponentUpdate
用于比较props和state的变化,决定UI是否更新,当组件比较多时,使用这个方法能有效提高应用性能。
componentWillUpdate
当props和state发生变化时执行,执行该函数,并且在render方法之前执行,紧接着这个函数就会调用render()来更新界面。
componentDidUpdate
组件更新结束之后执行,在初始化render时不执行。
void componentDidUpdate( object prevProps, object prevState )
componentWillReceiveProps
当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全的,并不会触发额外的render调用。
componentWillReceiveProps: function(nextProps) { this.setState({ likesIncreasing: nextProps.likeCount > this.props.likeCount }); }
componentWillUnmount
当组件要被从界面上移除的时候,就会调用componentWillUnmount(),在这个函数中,可以做一些组件相关的清理工作,例如取消计时器、网络请求等。
PureComponent
上面为大家讲了Component的生命周期,仔细阅读可以发现,在React 的Component的生命周期中,有一个shouldComponentUpdate方法,该方法默认返回值是true。Component的shouldComponentUpdate函数源码如下:
shouldComponentUpdate(nextProps, nextState) { return true; }
也就是说,不管有没有改变组件的props或者state属性,都需要调用shouldComponentUpdate()
来重绘界面,这极大的降低了React的渲染效率。因此,从React在15.3版本中发布了一个优化的PureComponent组件来优化React的渲染效率。而PureComponent的shouldComponentUpdate是这样的。
if (this._compositeType === CompositeTypes.PureClass) { shouldUpdate = !shallowEqual(prevProps, nextProps) || ! shallowEqual(inst.state, nextState); }
PureComponent使用浅比较判断组件是否需要重绘,因此,下面对数据的修改并不会导致重绘:
options.push(new Option()) options.splice(0, 1) options[i].name = "Hello"
这些例子都是在原对象上进行修改,由于浅比较是比较指针的异同,所以会认为不需要进行重绘。
为了避免出现这些问题,推荐使用immutable.js。immutable.js会在每次对原对象进行添加,删除,修改使返回新的对象实例,任何对数据的修改都会导致数据指针的变化。
实例
下面,我们通过一个实例来比较下PureComponent和Component在页面渲染上面的效率。
import React, { PureComponent,Component } from 'react'; import { AppRegistry, StyleSheet, Text, View, Button } from 'react-native'; export default class test extends PureComponent { constructor(props){ super(props); this.state = { number : 1, numbers: [], }; } render() { return ( <View style={styles.container}> <Button title={'number + 1'} onPress={this.numberAdd.bind(this)} /> <Text>number value: {this.state.number}</Text> <Button title={'numbers + 1'} onPress={this.numbersAdd.bind(this)} /> <Text>numbers length: {this.state.numbers.length}</Text> </View> ); } numberAdd(){ this.setState({number: ++this.state.number }); } numbersAdd(){ let numbers = this.state.numbers; numbers.push(1); this.setState({numbers: numbers}); console.log(this.state.numbers); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, }); AppRegistry.registerComponent('test', () => test);
如何让PureComponent重绘
当然,有时候如果继承PureComponent后需要在变化的时候重绘界面,我们要怎么做?
重写shouldUpdateComponent方法;
props或者state增减参数;
关于Component与PureComponent的内容就为大家介绍到这里,一句话:PureComponent是Component的一个优化组件,通过减少不必要的 render操作的次数,从而提高界面的渲染性能。
本文转载自异步社区
原文链接:https://www.epubit.com/articleDetails?id=N4693897b-0c08-460d-b069-687afa8dc940
- 点赞
- 收藏
- 关注作者
评论(0)