React Native之組件Component與PureComponent

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 stylex={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操作的次數,從而提高界面的渲染性能。


推薦閱讀:

React、Angular和Vue.js三者中哪一個更易學,更容易理解?
移動應用開發入門,是否可以考慮先學習 React Native?
react native 真機調試apk無法安裝到設備?
有哪些 React Native 開發的作品推薦嗎?
碼農如何從零開始做出有設計感的app?

TAG:前端開發 | ReactNative | 前端框架 |