在React Native中使用組件來封裝界面模塊時,整個界面就是一個大的組件,開發過程就是不斷優化和拆分界面組件、構造整個組件樹的過程。


上張圖涵蓋了一個組件從創建、運行到銷毀的整個過程。大家可以看到,初始化的時候會調用5個函數(按先后順序)。這5個函數在整個組件被創建到銷毀的過程中只調用一次。初始化完畢后,當組件的props或者state改變都會觸發不同的鈎子函數,繼而引發組件的重新渲染。現在我們把這過程拆開一點一點來分析。
初始化
我們先來看初始化,在初始化的過程中,會按順序調用下面5個函數。
getDefaultProps:組件實例創建前調用,多個實例間共享引用。注意:如果父組件傳遞過來的Props和你在該函數中定義的Props的key一樣,將會被覆蓋。
在組件中,我們可以利用this.props獲取在這里初始化它的屬性,由於組件初始化后,再次使用該組件不會調用getDefaultProps函數,所以組件自己不可以修改props,只可由其他組件調用它時再外部進行修改。
getInitalState:組件示例創建的時候調用的第一個函數。主要用於初始化state。注意:為了在使用中不出現空值,建議初始化state的時候盡可能給每一個可能用到的值都賦一個初始值。
該函數不同於getDefaultProps,在以后的過程中,會再次調用,所以可以將控制控件狀態的一些變量放在這里初始化,比如控件上顯示的文字,可以通過this.state來獲取值,通過this.setState來修改state值。注意:一旦調用了this.setState方法,組件一定會調用render方法,對組件進行再次渲染,不過,React框架會根據DOM的狀態自動判斷是否需要真正渲染。
componentWillMount:在render前,getInitalState之后調用。僅調用一次,可以用於改變state操作。
render:組件渲染函數,會返回一個Virtual DOM,只允許返回一個最外層容器組件。render函數盡量保持純凈,只渲染組件,不修改狀態,不執行副操作(比如計時器)。 componentDidMount:在render渲染之后,React會根據Virtual DOM來生成真實DOM,生成完畢后會調用該函數。
在瀏覽器端(React),我們可以通過this.getDOMNode()來拿到相應的DOM節點。然而我們在RN中並用不到,在RN中主要在該函數中執行網絡請求,定時器開啟等相關操作
在調用了render方法,組件加載成功並被成功渲染出來之后,所要執行的后續操作,一般都會在這個函數中進行,比如經常要面對的網絡請求等加載數據操作
運行中
初始化完成之后,組件將會進入到運行中狀態,運行中狀態我們將會遇到如下幾個函數:
componentWillReceiveProps(nextProps):props改變(父容器來更改或是redux),將會調用該函數。新的props將會作為參數傳遞進來,老的props可以根據this.props來獲取。我們可以在該函數中對state作一些處理。注意:在該函數中更新state不會引起二次渲染。
boolean shouldComponentUpdate(object nextProps, object nextState):該函數傳遞過來兩個參數,新的state和新的props。state和props的改變都會調到該函數。該函數主要對傳遞過來的nextProps和nextState作判斷。如果返回true則重新渲染,如果返回false則不重新渲染。在某些特定條件下,我們可以根據傳遞過來的props和state來選擇更新或者不更新,從而提高效率。
componentWillUpdate(object nextProps, object nextState):與componentWillMount方法類似,組件上會接收到新的props或者state渲染之前,調用該方法。但是不可以在該方法中更新state和props。
render:跟初始化的時候功能一樣。
componentDidUpdate(object prevProps,object prevState):和初始化時期的componentDidMount類似,在render之后,真實DOM生成之后調用該函數。傳遞過來的是當前的props和state。在該函數中同樣可以使用this.getDOMNode()來拿到相應的DOM節點。如果你需要在運行中執行某些副操作,請在該函數中完成。
銷毀
銷毀階段只有一個函數,很簡單
componentWillUnmount:組件DOM中移除的時候調用。在這里進行一些相關的銷毀操作,比如定時器,監聽等等。
案例代碼
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity
} from 'react-native';
import {Actions} from 'react-native-router-flux';
import Student from './Student';
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
clickText: "開始點擊按鈕",
count: 1,
detailContent: true
}
}
componentWillMount() {
console.log("componentWillMount1111");
}
shouldComponentUpdate(nextProps, nextState){
console.log(this.state.detailContent,'detailContent');
if (this.state.count !== nextState.count) {
console.log("shouldComponentUpdate1111---組件需要更新");
return true;
}
return false;
}
componentWillUpdate(){
console.log("componentWillUpdate1111---組件將要更新");
}
componentDidUpdate(){
console.log("componentDidUpdate1111---組件更新完畢");
}
componentDidMount() {
console.log("componentDidMount1111");
}
componentWillUnmount() {
console.log("componentWillUnmount1111");
}
clickButton(){
const { count } = this.state;
this.setState({
clickText: "我點擊了按鈕",
count: count + 1,
detailContent: false
})
}
render() {
console.log("render1111");
return (
<View style={styles.container}>
<Text>歡迎來到首頁</Text>
<TouchableOpacity
onPress={() => Actions.notice()}
>
<Text>跳轉到公告頁</Text>
</TouchableOpacity>
<Text style={{color: 'blue', fontSize: 40}}>{this.state.count}</Text>
<TouchableOpacity
style={styles.button}
onPress={() => this.clickButton()}
>
<Text>{this.state.clickText}</Text>
</TouchableOpacity>
<Student detailContent={this.state.detailContent}/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
},
button: {
width: 250,
height: 60,
backgroundColor: 'red',
borderRadius: 10,
alignItems: 'center',
justifyContent: 'center'
}
});
import React, {Component} from 'react';
import {
View,
Text,
StyleSheet
} from 'react-native';
export default class Student extends Component {
constructor(props) {
super(props);
this.state = {}
}
componentWillMount() {
}
componentWillReceiveProps(nextProps){
console.log(this.props.detailContent,'this--->>componentWillReceiveProps');
console.log(nextProps.detailContent,'next--->>componentWillReceiveProps')
}
componentDidMount() {
}
componentWillUnmount() {
}
render() {
return (
<View style={styles.container}>
<Text>歡迎HomeDetails</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center"
}
});
