React Native真的是越來越流行,沒使用React Native開發(fā)項目都不好意思說自己是搞客戶端開發(fā)的观堂。對于純Native開發(fā)者來說氮凝,剛上手React Native有一定的適應期凹蜂,如果JavaScript也不熟練的話那就更悲催了弟头。React Native涉及ES6,React語法踩验,JSX鸥诽,前端調試,Native客戶端等知識箕憾,本文簡單總結了React Native開發(fā)中一些知識點牡借。算是在學習中的積累。
Component
Component:組件袭异,使用React.createClass
或者extends React.Component
創(chuàng)建的類為組件钠龙。
Element:元素或者可以說是組件的實例,使用<Label />
或者let label = new Label()
創(chuàng)建的為實例御铃。
對于定義組件碴里,React以前版本的寫法(ES5):
var Lable = React.createClass({
render(){
}
});
React最新的寫法(ES6):
class Label extends React.Component{
render(){
}
}
props與state
props屬性:組件可以定義初始值,自己不可更改props屬性值上真,只允許從父組件中傳遞過來:
// 父組件
class MainComponent extends React.Component{
render(){
return(<Label name="標題欄">);
}
}
// 子組件
class Label extends React.Component{
render(){
return(<Text>{this.props.name}</Text>);
}
}
父組件向Label傳遞name="標題欄"的props屬性咬腋,在Label中使用this.props.name引用此屬性。
state屬性:組件用來改變自己狀態(tài)的屬性睡互,通常使用setState({key:value})
來改變屬性值根竿,不能使用this.state.xxx
來直接改變陵像,setState({key:value})
方法會觸發(fā)界面刷新。
對于經常改變的數(shù)據(jù)且需要刷新界面顯示寇壳,可以使用state醒颖。對于不需要改變的屬性值可以使用props。React Native建議由頂層的父組件定義state值壳炎,并將state值作為子組件的props屬性值傳遞給子組件泞歉,這樣可以保持單一的數(shù)據(jù)傳遞。
在以前版本的React中定義state匿辩,props可以使用生命周期方法 getInitialState()
和getInitialState()
:
var Label = React.createClass({
getInitialState(){
key:value,
...
},
getInitialProps(){
key:value,
...
},// 這種寫法需要有疏日,不要使用;
render:funation(){
}
});
在最新版本的React可以使用構造函數(shù)替代getInitialState()撒汉,getInitialState()方法定義初始值:
class Label extends React.Component{
constructor(props) {
super(props);
this.state = {
time: '2016',
city: '上海',
};
this.props = {
name:'標題',
};
}
}
默認props與props校驗
class Label extends React.Component{
constructor(props) {
super(props);
}
// 默認props
static defaultProps = {
city: '南京',
index: 12,
}
// propTypes用于驗證轉入的props,當向 props 傳入無效數(shù)據(jù)時涕滋,JavaScript 控制臺會拋出警告
static propTypes = {
city: React.PropTypes.string.isRequired,
index: React.PropTypes.number.isRequired,
}
state = {
city: this.props.city,
index:this.props.index,
}
}
// or
class Label extends React.Component{
constructor(props) {
super(props);
}
}
// 默認props
Label.defaultProps = {
city: '南京',
index: 12,
}
// propTypes用于驗證轉入的props睬辐,當向 props 傳入無效數(shù)據(jù)時,JavaScript 控制臺會拋出警告
Label.propTypes = {
city: React.PropTypes.string.isRequired,
index: React.PropTypes.number.isRequired,
}
生命周期
我們把組件從裝載
,到渲染
宾肺,再到卸載
當做一次生命周期溯饵,也就是組件的生存狀態(tài)從裝載
開始到卸載
為止,期間可以根據(jù)屬性的變化進行多次渲染锨用。
生命周期的三種狀態(tài):
- Mounting:裝載丰刊,
- Updating:渲染
- Unmounting:卸載
componentWillMount(),組件開始裝載之前調用增拥,在一次生命周期中只會執(zhí)行一次啄巧。
componentDidMount(),組件完成裝載之后調用掌栅,在一次生命周期中只會執(zhí)行一次秩仆,從這里開始就可以對組件進行各種操作了,比如在組件裝載完成后要顯示的時候執(zhí)行動畫猾封。
componentWillUpdate(object nextProps, object nextState)澄耍,組件屬性更新之前調用,每一次屬性更新都會調用
componentDidUpdate(object prevProps, object prevState)晌缘,組件屬性更新之后調用齐莲,每次屬性更新都會調用
componentWillUnmount(),組件卸載之前調用
組件屬性更改時會調用以下方法磷箕,在一次生命周期中可以執(zhí)行多次:
componentWillReceiveProps(object nextProps)选酗,已加載組件收到新的參數(shù)時調用
shouldComponentUpdate(object nextProps, object nextState),組件判斷是否重新渲染時調用
頁面跳轉
初始化第一個頁面:
import SeatPageComponent from './SeatPageComponent';
import MainPageComponent from './MainPageComponent';
import TrainListComponent from './TrainListComponent';
class MainPage extends React.Component {
render() {
let defaultName = 'MainPageComponent';
let defaultComponent = MainPageComponent;
return (
<Navigator
// 指定默認頁面
initialRoute={{ name: defaultName, component: defaultComponent }}
// 配置頁面間跳轉動畫
configureScene={(route) => {
return Navigator.SceneConfigs.VerticalDownSwipeJump;
}}
// 初始化默認頁面
renderScene={(route, navigator) => {
let Component = route.component;
// 將navigator作為props傳遞到下一個頁面
return <Component {...route.params} navigator={navigator} />
}} />
);
}
}
跳轉到下一頁面:
jumpToNext(){
const { navigator } = this.props;// 由上一個頁面?zhèn)鬟f過來
if(navigator) {
navigator.push({
name: 'SeatPageComponent',
component: SeatPageComponent,// 下一個頁面
});
}
}
返回上一個頁面:
_back(){
const { navigator } = this.props;
if(navigator) {
navigator.pop();
}
}
頁面間通信
例如:從A頁面打開B頁面
A通過route.params將參數(shù)傳遞給B:
jumpToNext(){
const { navigator } = this.props;// 由上一個頁面?zhèn)鬟f過來
if(navigator) {
navigator.push({
name: 'SeatPageComponent',
component: SeatPageComponent,// 下一個頁面
params: { // 需要傳遞個下一個頁面的參數(shù),第二個頁面使用this.props.xxx獲取參數(shù)
id: 123,
title: this.state.title,
},
});
}
}
A通過route.params傳遞回調方法或者A的引用來讓B將數(shù)據(jù)傳回給A:
// A頁面
jumpToNext(){
const { navigator } = this.props;// 由上一個頁面?zhèn)鬟f過來
if(navigator) {
let that = this;// this作用域岳枷,參見下文函數(shù)綁定
navigator.push({
name: 'SeatPageComponent',
component: SeatPageComponent,// 下一個頁面
params: { // 需要傳遞個下一個頁面的參數(shù),第二個頁面使用this.props.xxx獲取參數(shù)
title: '測試',
getName: function(name) {that.setState({ name: name })}
},
});
}
}
// B頁面
_back(){
const { navigator } = this.props;
if(this.props.getName){
this.props.getName('測試');
}
if(navigator) {
navigator.pop();
}
}
組件間通信
父組件-->子組件星掰, 使用props多望,父組件向子組件傳遞props
// 父組件
class MainComponent extends React.Component{
render(){
return(<Label name="標題欄">);
}
}
// 子組件
class Label extends React.Component{
render(){
return(<Text>{this.props.name}</Text>);
}
}
子組件-->父組件, 父組件在創(chuàng)建子組件時傳遞回調方法
// 父組件
class MainComponent extends React.Component{
constructor(props) {
super(props);
this.state = {
name: '測試',
};
}
// 回調方法
getName(str){
this.setState({name:str});
}
render(){
return(<Label name="標題欄" getName={getName}/>);
}
}
// 子組件
class Label extends React.Component{
render(){
return(
<View>
<TouchableOpacity onPress={()=>this._onPress()}>
<Text>點我氢烘,{this.props.name}</Text>
</TouchableOpacity>
</View>);
}
_onPress(){
if(this.props.getName){
this.props.getName('測試')
}
}
}
非父子關系的組件怀偷,即沒有任何嵌套關系的組件, 可以引入訂閱源(js-signals, PubSubJS)播玖,監(jiān)聽訂閱事件椎工。例如,在生命周期方法中addEventListener()蜀踏,removeEventListener()维蒙,在合適時機setState()。
ECMAScript
ES6中函數(shù)的寫法:
class Label extends React.Component{
doSomething(){
//...
}// 不要使用逗號或者分號作為結尾
}
key:value形式定義函數(shù)的寫法:
var Label = React.createClass({
doSomething:funation(){
//......
},// 需要使用逗號作為結尾果覆,不能使用分號
doSomething2:function(){
//......
},
});
函數(shù)綁定
class Label extends React.Component{
// 有函數(shù)
sayHello(str){
console.log(str)
}
// 在onPress中使用箭頭函數(shù)調用
// onPress={() => this.sayHello('Hello')}
// 等同于
//onPress={sayHello('hello').bind(this)}
// 等同于
// onPress={print('hello',this)}
render(){
return (
<View>
<TouchableOpacity onPress={() => this.sayHello('Hello')}>
<Text>點我</Text>
</TouchableOpacity>
</View>
)
}
function print(str,this){
let that = this;// 注意這里this的生命周期
function say(str){
that.sayHello(str)// 此處不能再使用this
}
say(str);
}
}
Tips
require颅痊,import:javascript的模塊管理工具,管理各個模塊之間的引用局待,解決javascript異步加載的問題斑响,解決js寫成多個文件后瀏覽器加載緩慢的問題。
JavaScript中沒有private钳榨,public的概念
使用_開頭的方法代表private方法舰罚,不適用則表示public方法
class Label extends Component{
// private 函數(shù)
_doSomething(){
//......
}
// public 函數(shù)
doSomething(){
//......
}
}
參考資料
Reactjs中文教程
極客學院React教程
ECMAScript語法
JavaScript模塊系統(tǒng)
require.js
Navigator
結合ES6+開發(fā)React
React組件通信