React-Native生命週期
開發中組件免不了要與用戶互動,React 的一大創新,就是將組件看成是一個狀態機,一開始有一個初始狀態,然後用戶互動,導致狀態變化,從而觸發重新渲染 UI。下圖爲ReactNative中組件的生命週期,根據執行順序在對應的函數中做對應的操作
這張經典的圖描述了ReactNative組件從創建、運行到銷燬的整個過程,其中經常用到的是創建過程,初始化的時候會調用5個函數,這5個函數在整個組件創建到銷燬的過程中只調用一次。
初始化過程
getDefaultProps (ES6廢除了這樣的寫法)
- 該函數用於初始化一些默認的屬性,通常會將固定的內容放在這個函數 中進行初始化和賦值,一般放置一些常量
- 在組件中,可以利用
this.props
獲取在這裏初始化它的屬性 - 由於組件初始化後,再次使用該組件不會調用getDefaultProps函數,所以組件自己不可以自己修改props(即:props可認爲是隻讀的),只可由其他組件調用它時在外部修改。
- 注意:如果父組件傳遞過來的Props和你在該函數中定義的Props的key一樣,將會被覆蓋
getInitalState(ES6廢除了這樣的寫法)
- 該函數是用於對組件的一些狀態進行初始化,一般放置一些變量
- 由於該函數不同於getDefaultProps,在以後的過程中,會再次調用
- 所以可以將控制控件的狀態的一些變量放在這裏初始化,可以通過
this.state
來獲取值、修改state值, 比如:
this.setState({
name:testName,
});
- 注意:
- 一旦調用了this.setState方法,組件一定會調用render方法,對組件進行再次的渲染,不過,如果React框架會自動根據DOM的狀態來判斷是否需要真正的渲染。只有改變纔會重新渲染,這種狀態被稱爲狀態機
- 爲了在使用中不出現空值,建議初始化state的時候儘可能給每一個可能用到的值都賦一個初始值。 -
componentWillMount
- 在render前,getInitalState之後調用。僅調用一次,可以用於改變state操作
- 相當於OC中的ViewWillAppear方法
render
- 組件渲染函數,會返回一個Virtual DOM,只允許返回一個最外層容器組件。render函數儘量保持純淨,只渲染組件,不修改狀態,不執行副操作(比如計時器)
- 在render函數中,只可通過this.state和this.props來訪問在之前函數中初始化的數據值
componentDidMount
- 在調用了render方法後,React會根據Virtual DOM來生成真實DOM,生成完畢後會調用該函數。
- 主要在該函數中執行網絡請求,定時器開啓等加載數據的操作
- 因爲UI已經成功被渲染出來, 所以放在這個函數裏進行請求操作,不會出現UI上的錯誤。
運行過程
componentWillReceiveProps
- props改變(父容器來更改或是redux),將會調用該函數。新的props將會作爲參數傳遞進來,老的props可以根據this.props來獲取。我們可以在該函數中對state作一些處理,其實就是指父元素對組件的props或state進行了修改
- 注意:在該函數中更新state不會引起二次渲染。
shouldComponentUpdate
- 該函數傳遞過來兩個參數,新的state和新的props。state和props的改變都會調到該函數。該函數主要對傳遞過來的nextProps和nextState作判斷。如果返回true則重新渲染,如果返回false則不重新渲染。在某些特定條件下,我們可以根據傳遞過來的props和state來選擇更新或者不更新,一般用於優化,提高效率。
componentWillUpdate
- 組件刷新前調用,類似componentWillMount
- 組件上會接收到新的props或者state渲染之前,調用該方法。但是不可以在該方法中更新state和props。
componentDidUpdate
- 和初始化時期的componentDidMount類似,在render之後,真實DOM生成之後調用該函數。傳遞過來的是當前的props和state。在該函數中同樣可以使用this.getDOMNode()來拿到相應的DOM節點。如果你需要在運行中執行某些副操作,請在該函數中完成
銷燬過程
componentWillUnmount
- 用於清理一些無用的內容。在這裏進行一些相關的銷燬操作,比如定時器,監聽等等
props和state
- 關於Props(ES6的寫法)
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Platform,
StyleSheet,
View,
Text,
} from 'react-native';
class BClass extends Component<{}> {
render() {
console.log('title變化',this.props.title);
return (
<View>
<Text>{this.props.title}</Text>
</View>
);
}
}
BClass.propTypes = {
title:PropTypes.String
};
BClass.defaultProps = {title:'xiaoming'};
export default class AClass extends Component<{}> {
render() {
return (
<View style={styles.container}>
{/* 顯示初始值 */}
<BClass />
{/* 變化值 */}
<BClass title = 'xiaobai'/>
</View>
);
}
}
定義了BClass且title的默認值爲xiaoming,然後通過它的父組件AClass給BClass中title賦值,然後打印log
log:
可以看出原先的xiaoming被修改成了xiaobai
- 關於State(ES6的寫法)
export default class AClass extends Component<{}> {
constructor(props){
super(props);
this.state = {
name : '000'
};
console.log('初始化' +'name:'+this.state.name + ' ' + 'age:'+this.state.age);
}
componentWillMount(){
this.setState({
name : 'AAA',
age:16
})
}
render() {
console.log('改變前' +'name:'+this.state.name + ' ' + 'age:'+this.state.age);
return (
<View style={styles.container}>
<Text>{this.state.name} </Text>
<Text>{this.state.age} </Text>
</View>
);
}
componentDidMount(){
this.setState({
name : 'BBB',
age:18
})
console.log('改變後' + 'name:'+this.state.name + ' ' + 'age:'+this.state.age);
}
}
可以看到,初始化之後
初始化一個state爲name,然後在componentWillMount函數和componentDidMount函數中改變已經初始化的name和沒有聲明age,打印出來
log:
當componentDidMount函數執行完之後依然會引發render再次渲染
關於Prop和State的區別,
相同點
1.不管是props還是state的改變,都會引發render的重新渲染。
2.都能由自身組件的相應初始化函數設定初始值。
不同點
1.初始值來源:state的初始值來自於自身的getInitalState(constructor)函數;props來自於父組件或者自身getDefaultProps(若key相同前者可覆蓋後者)。
2.修改方式:state只能在自身組件中setState,不能由父組件修改;props只能由父組件修改,不能在自身組件修改。
3.對子組件:props是一個父組件傳遞給子組件的數據流,這個數據流可以一直傳遞到子孫組件;state代表的是一個組件內部自身的狀態,只能在自身組件中存在。
盜用網上的一張圖: