通過編寫的第二篇文章可以成功創(chuàng)建一個(gè)新項(xiàng)目砂代,即直接利用以下語句創(chuàng)建:
//命令行創(chuàng)建項(xiàng)目:
react-native init AwesomeProject
創(chuàng)建成功后昼窗,剛?cè)腴T的我們主要關(guān)注兩個(gè)文件:
1)iOS項(xiàng)目目錄下的AppDelegate.m
為將iOS項(xiàng)目連接js文件的入口只嚣,以及相關(guān)初始化操作豺憔。
2)根目錄下的index.ios.js
為iOS對(duì)應(yīng)的js入口文件帅容。
一牍帚、 解析iOS項(xiàng)目中的AppDelegate.m
1. AppDelegate.m 代碼如下:
#import "AppDelegate.h"
// React Native相關(guān)頭文件
#import "RCTBundleURLProvider.h"
#import "RCTRootView.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
/*
當(dāng)應(yīng)用開始運(yùn)行的時(shí)候棍矛,RCTRootView將會(huì)從以下的URL中加載應(yīng)用:(本地調(diào)試的時(shí)候是直接在本地服務(wù)器中的index.ios加載安疗,發(fā)布時(shí)設(shè)置有所不同)
重新調(diào)用了你在運(yùn)行這個(gè)App時(shí)打開的終端窗口,它開啟了一個(gè) packager 和 server 來處理上面的請(qǐng)求够委。
在 Safari 中打開那個(gè) URL荐类;你將會(huì)看到這個(gè) App 的 JavaScript 代碼
*/
[[RCTBundleURLProvider sharedSettings] setDefaults];
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
// RCTRootView是一個(gè)UIView容器,承載著React Native應(yīng)用茁帽。同時(shí)它也提供了一個(gè)聯(lián)通原生端和被托管端的接口玉罐。
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"AwesomeProject"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
2. RCTRootView
RCTRootView將React Natvie視圖封裝到原生組件中。(用戶能看到的一切內(nèi)容都來源于這個(gè)RootView潘拨,所有的初始化工作也都在這個(gè)方法內(nèi)完成吊输。)
解析:
通過RCTRootView的初始化函數(shù)你可以將任意屬性傳遞給React Native應(yīng)用。
參數(shù)initialProperties必須是NSDictionary的一個(gè)實(shí)例铁追。
這一字典參數(shù)會(huì)在內(nèi)部被轉(zhuǎn)化為一個(gè)可供JS組件調(diào)用的JSON對(duì)象季蚂。
NSArray *imageList = @[@"http://foo.com/bar1.png",
@"http://foo.com/bar2.png"];
NSDictionary *propsDict = @{@"images" : imageList};
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"AwesomeProject"
initialProperties: propsDict
launchOptions:launchOptions];
在js文件中,則是通過this.props.images調(diào)用上面定義的參數(shù)脂信。
this為AppRegistry.registerComponent注冊(cè)的組件(下面會(huì)講到)
RCTRootView同樣提供了一個(gè)可讀寫的屬性appProperties癣蟋。在appProperties設(shè)置之后,React Native應(yīng)用將會(huì)根據(jù)新的屬性重新渲染狰闪。當(dāng)然疯搅,只有在新屬性和之前的屬性有區(qū)別時(shí)更新才會(huì)被觸發(fā)。
(注意:1.可以隨時(shí)更新屬性埋泵,但是更新必須在主線程中進(jìn)行幔欧,讀取則可以在任何線程中進(jìn)行。2.更新屬性時(shí)并不能做到只更新一部分屬性)
NSArray *imageList = @[@"http://foo.com/bar3.png",
@"http://foo.com/bar4.png"];
rootView.appProperties = @{@"images" : imageList};
二丽声、解析js入口文件(index.ios.js)
1. index.ios.js 代碼如下:
'use strict'; // 全局進(jìn)入嚴(yán)格模式(目前發(fā)現(xiàn)不用也行)
/**<
消除Javascript語法的一些不合理礁蔗、不嚴(yán)謹(jǐn)之處,減少一些怪異行為;
消除代碼運(yùn)行的一些不安全之處雁社,保證代碼運(yùn)行的安全浴井;
提高編譯器效率,增加運(yùn)行速度霉撵;
為未來新版本的Javascript做好鋪墊磺浙。
*/
//導(dǎo)入一些必要的模塊
//React Native內(nèi)置的組件可以直接通過import { xxx } from 'react-native' 進(jìn)行導(dǎo)入洪囤,當(dāng)然也可以自定義組件。
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableOpacity
} from 'react-native';
//類撕氧,這是默認(rèn)的載入類瘤缩,繼承自Component,Component類(組件)似于Android和iOS中的View
//這里為創(chuàng)建一個(gè)組件
class AwesomeProject extends Component {
//構(gòu)造器 伦泥,每個(gè)組件都擁有自己的屬性(props)和狀態(tài)(state)
//調(diào)用this.setState更改狀態(tài)text或者isTouchDown時(shí)剥啤,組件會(huì)觸發(fā)render函數(shù)進(jìn)行渲染更新
constructor(props) {
super(props);
this.state = {
text:'Welcome to React Native!',
isTouchDown:false
};
}
//在最初的渲染之前調(diào)用一次,可在里面進(jìn)行預(yù)處理操作
//在React中不脯,設(shè)置this.state會(huì)導(dǎo)致重新渲染府怯,但是componentWillMount設(shè)置this.state并不會(huì)對(duì)導(dǎo)致render調(diào)用多次
//之后會(huì)對(duì)component的生命周期進(jìn)一步解釋
componentWillMount() {
}
//渲染函數(shù),用來渲染實(shí)際的Component可視部分
render() {
//var定義變量跨新,根據(jù)狀態(tài)值改變對(duì)應(yīng)值
var welcomeText = this.state.text;
var bgcolor;
if (this.state.isTouchDown) {
bgcolor = '#c5c5ab';
} else {
bgcolor = '#F5FCFF';
}
console.log('testtststststts');
//返回的即界面顯示內(nèi)容
return (
<View style={[styles.container, {backgroundColor: bgcolor}]}>
<Text style={styles.welcome}>
{welcomeText}
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Shake or press menu button for dev menu
</Text>
<TouchableOpacity onPress={this.touchDown.bind(this)}>
<Text style={[styles.instructions, {backgroundColor: 'green'}]}>
test touch Me
</Text>
</TouchableOpacity>
</View>
);
}
// 自定義函數(shù)
touchDown() {
// console.log 控制臺(tái)打印富腊,可打印值涕烧,多用于調(diào)試
console.log('>>', this.isTouchDown);
if (!this.state.isTouchDown) {
this.setState({
text:'Test Touch Down Success',
isTouchDown:true
});
} else {
this.setState({
text:'Test Touch Down Again Success',
isTouchDown:false
});
}
}
}
//定義樣式
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 定義了App的入口与涡,并提供了根組件稚铣。
//第一個(gè)'AwesomeProject'要與AppDelegate里注冊(cè)的moduleName一致
//第二個(gè)AwesomeProject則是入口組件,即上面定義的Component類
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
2. 運(yùn)行效果:
3. 基礎(chǔ)概念解釋
1)組件
代碼中的 Text, View, TouchableOpacity均為基礎(chǔ)組件肖揣。AwesomeProject則是自己創(chuàng)建的組件,也作為項(xiàng)目的入口組件浮入。
在React Native項(xiàng)目中龙优,所有展示的界面,都可以看做是一個(gè)組件(Component)只是功能和邏輯上的復(fù)雜程度不同事秀。每一個(gè)是許許多多小的組件拼成的彤断,每個(gè)小的組件也有自己對(duì)應(yīng)的邏輯。
2)組件的狀態(tài)與屬性
組件本質(zhì)上是狀態(tài)機(jī)易迹,輸入確定宰衙,輸出一定確定。組件把狀態(tài)與結(jié)果一一對(duì)應(yīng)起來睹欲,組件中有state與prop(狀態(tài)與屬性)供炼。
屬性(props)是標(biāo)簽里面的屬性, 組件之前通過標(biāo)簽的屬性來傳遞數(shù)據(jù),由父組件傳遞給子組件(單向的屬性傳遞)窘疮。
如果component的某些狀態(tài)由外部所決定袋哼,并且會(huì)影響到component的render,那么這些狀態(tài)就應(yīng)該用props表示闸衫。
例如:一個(gè)下拉菜單的component涛贯,有哪些菜單項(xiàng),是由這個(gè)component的使用者和使用場(chǎng)景決定的蔚出,那么“菜單項(xiàng)”這個(gè)狀態(tài)弟翘,就應(yīng)該用props表示含懊,并且由外部傳入。
狀態(tài)(state)是子組中的狀態(tài)衅胀,內(nèi)部的事件方法或者生命周期方法都可以調(diào)用this.setState來變更岔乔,當(dāng)狀態(tài)發(fā)生變化的同時(shí),組件也會(huì)觸發(fā)render函數(shù)進(jìn)行渲染更新滚躯。
如果component的某些狀態(tài)需要被改變雏门,并且會(huì)影響到component的render,那么這些狀態(tài)就應(yīng)該用state表示掸掏。
例如:一個(gè)購(gòu)物車的component茁影,會(huì)根據(jù)用戶在購(gòu)物車中添加的產(chǎn)品和產(chǎn)品數(shù)量,顯示不同的價(jià)格丧凤,那么“總價(jià)”這個(gè)狀態(tài)募闲,就應(yīng)該用state表示。
這篇文章利用了一個(gè)很簡(jiǎn)單的例子去具體解析了React Native的基本代碼愿待,最主要想理解組件的概念浩螺,由此可以更好的去理解別人的代碼,仍侥,接下去為了更好的入門要出,會(huì)繼續(xù)寫兩篇文章分別介紹React Native用到的js基礎(chǔ)、react基礎(chǔ)农渊,以及介紹組件的生命周期患蹂。
正在寫React Native的學(xué)習(xí)教程ing,是一邊研究一邊編寫的砸紊,已有的成果如下:
1) React Native 簡(jiǎn)介與入門
2) React Native 環(huán)境搭建和創(chuàng)建項(xiàng)目(Mac)
3) React Native 開發(fā)之IDE