創建一個Component
一個組件類可以像前面Hello World工程中那樣通過 class HelloWorldAppp extends Component 來創建,或者通過React.createClass來創建,並且提供一個render方法以及其他可選的生命週期函數、組件相關的事件或方法定義。
因此,HelloWorldAppp和下面的實現方法是等價的:
var HelloWorldAppp = React.createClass({
render() {
return (
<View
</View>
);
},
});
通過繼承Component實現的組件中如果實現getDefaultProps getInitialState等方法時,會有下面警告:
Warning: getDefaultProps was defined on HelloWorldAppp, a plain JavaScript class. This is only supported for classes created using React.createClass. Use a static property to define defaultProps instead.
React組件生命週期
先來看一段代碼:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
Image,
TouchableHighlight
} from 'react-native';
var clickTime = 0;
var HelloWorldAppp = React.createClass({
getDefaultProps(){
console.log("getDefaultProps")
return {title:"HelloWorld"}
},
getInitialState(){
console.log("getInitialState")
return {content:"點擊屏幕任意位置"}
},
componentWillMount(){
console.log("componentWillMount")
},
componentDidMount(){
console.log("componentDidMount")
},
shouldComponentUpdate(nextProps,nextState){
console.log("shouldComponentUpdate")
return true
},
componentWillUpdate(nextProps,nextState){
console.log("componentWillUpdate")
},
componentDidUpdate(prevProps,prevState){
console.log("componentDidUpdate")
},
render() {
console.log("render")
return (
<TouchableHighlight
onPress={() => this.backgorundClicked()}
underlayColor = '#ddd'
style = {styles.container}
>
<Text style={styles.welcome}>{clickTime > 0 ? this.state.content : this.props.title + " \n " + this.state.content}</Text>
</TouchableHighlight>
);
},
backgorundClicked(){
clickTime++
this.setState({
content:"第"+clickTime+"次點擊"
});
}
});
AppRegistry.registerComponent('AwesomeProject', () => HelloWorldAppp);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
title_text:{
fontSize:18,
}
});
然後認識一下組件中的一些函數:
- getDefaultProps: 用來設置組件屬性的默認值。通常會將固定的內容放在這個過程中進行初始化和賦值,一個控件可以利用this.props獲取在這裏初始化它的屬性,由於組件初始化後,再次使用該組件不會調用getDefaultProps函數,所以組件自己不可以自己修改props(即:props可認爲是隻讀的),只可由其他組件調用它時在外部修改。
getDefaultProps並不是在組件實例化時被調用,而是在createClass時被調用,返回值會被緩存。也就是說,不能在getDefaultProps中使用任何特定的實例數據。 - getInitialState: 這裏是對控件的一些狀態進行初始化,由於該函數不同於getDefaultProps,在以後的過程中,會再次調用,所以可以將控制控件的狀態的一些變量放在這裏初始化,如控件上顯示的文字,可以通過this.state來獲取值,通過this.setState來修改state值,修改方式如下:
this.setState({
content:"第"+clickTime+"次點擊"
});
值得注意的是,一旦調用了this.setState方法,控件必將調用render方法,對控件進行再次的渲染,不過,React框架會自動根據DOM的狀態來判斷是否需要真正的渲染。
- render:上面已經說過render是一個組件必須有的方法,形式爲一個函數,並返回JSX或其他組件來構成DOM,和Android的XML佈局、WPF的XAML佈局類似,只能返回一個頂級元素。
生命週期函數
- 裝載組件
- componentWillMount:這個方法被調用時期是組件將要被加載在視圖上之前,功能比較少,即:render一個組件前最後一次修改state的機會。
- componentDidMount:即調用了render方法後,組件加載成功並被成功渲染出來以後所執行的hook函數,一般會將網絡請求等加載數據的操作,放在這個函數裏進行,來保證不會出現UI上的錯誤.
- 更新組件狀態
存在期主要是用來處理與用戶的交互,如:點擊事件,都比較簡單,也不是很常用,具體有以下幾個過程:
- componentWillReceiveProps:指父元素對組件的props或state進行了修改。
- shouldComponentUpdate:一般用於優化,可以返回false或true來控制是否進行渲染
- componentWillUpdate:組件刷新前調用,類似componentWillMount
- componentDidUpdate:更新後的hook
- 卸載(刪除)組件
銷燬期,用於清理一些無用的內容,如:點擊事件Listener。
- componentWillUnmount
上面函數的調用順序是:
- 創建時
getDefaultProps
getInitialState
componentWillMount
render
componentDidMount - 更新shi
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
總得來講,React Native組件的生命週期,經歷了Mount->Update->Unmount這三個大的過程,即從創建到銷燬的過程,如果藉助Android和iOS的開發思想,那麼React Native組件的生命週期就更容易理解了。那麼,我們構建一個React Native控件也就能夠知道如何下手,如何控制和優化。經過一層一層的封裝和調用,一個完整的React Native應用也就構建出來了。
Props(屬性)和 State(狀態)
Props 就是組件的屬性,由外部通過 JSX 屬性傳入設置,一旦初始設置完成,就可以認爲 this.props 是不可更改的,所以不要輕易更改設置 this.props 裏面的值(雖然對於一個 JS 對象你可以做任何事)。
class MyText extends Component{
render() {
return(
<Text style={this.props.style}>{this.props.content}</Text>
);
}
}
class HelloWorldAppp extends Component{
render() {
return (
<MyText style={styles.welcome} content="HelloWorld"/>
);
}
}
State 是組件的當前狀態,可以把組件簡單看成一個“狀態機”,根據狀態 state 呈現不同的 UI 展示。一旦狀態(數據)更改,組件就會自動調用 render 重新渲染 UI,這個更改的動作會通過 this.setState 方法來觸發。
class HelloWorldAppp extends Component{
constructor(props) {
super(props);
this.state = {showText:"Test"};
}
render() {
return (
<View>
<Text style={styles.title_text}>{this.state.showText}</Text>
</View>
);
}
}
refs
ref是React中的一種屬性,當render函數返回某個組件的實例時,可以給render中的某個虛擬DOM節點添加一個ref屬性。要獲取一個React組件的引用,可以使用ref來獲取你擁有的子組件的引用。
var HelloWorldAppp = React.createClass({
render() {
console.log("render");
return (
<View style={styles.container}>
<TextInput style={styles.welcome} ref="mytestinput"></TextInput>
<Text style={styles.welcome} onPress={this.blur}>清除焦點</Text>
<Text style={styles.welcome} onPress={this.focus}>獲取焦點</Text>
</View>
);
},
focus(){
if(this.refs.mytestinput != null){
this.refs.mytestinput.focus();
}
},
blur(){
if(this.refs.mytestinput != null){
this.refs.mytestinput.blur();
}
}
});
在這個例子中,我們通過this.refs.mytestinput獲取輸入框實例,來實現獲取焦點和清除焦點。
組件之間通信
通過上面的講解我們可以知道:
- 父組件調用子組件:可以通過
this.props
方法。 - 子組件調用父組件:通過回調函數;
- 兄弟組件:通過其父組件;通過
ref
來實現; - 沒有關聯的組件:通過發送事件:Event Emitter/Target/Dispatcher或者可以通過
ref
來實現。 - Redux
- Flux
這部分後面再介紹。