4) React Native 入門項(xiàng)目與解析

通過編寫的第二篇文章可以成功創(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)行效果:

簡(jiǎn)單運(yùn)行效果.png

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

  1. React Native 入門項(xiàng)目與解析
    5) React Native 相關(guān)JS和React基礎(chǔ)
    6) React Native 組件生命周期(ES6)
    7) React Native 集成到原生項(xiàng)目(iOS)
    8) React Native 與原生之間的通信(iOS)
    9) React Native 封裝原生UI組件(iOS)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末传于,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子醉顽,更是在濱河造成了極大的恐慌沼溜,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件徽鼎,死亡現(xiàn)場(chǎng)離奇詭異盛末,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)否淤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門悄但,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人石抡,你說我怎么就攤上這事檐嚣。” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵嚎京,是天一觀的道長(zhǎng)嗡贺。 經(jīng)常有香客問我,道長(zhǎng)鞍帝,這世上最難降的妖魔是什么诫睬? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮帕涌,結(jié)果婚禮上摄凡,老公的妹妹穿的比我還像新娘。我一直安慰自己蚓曼,他們只是感情好亲澡,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纫版,像睡著了一般床绪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上其弊,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天癞己,我揣著相機(jī)與錄音,去河邊找鬼瑞凑。 笑死末秃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的籽御。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼惰匙,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼技掏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起项鬼,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤哑梳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后绘盟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鸠真,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年龄毡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吠卷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡沦零,死狀恐怖祭隔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情路操,我是刑警寧澤疾渴,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布千贯,位于F島的核電站,受9級(jí)特大地震影響搞坝,放射性物質(zhì)發(fā)生泄漏搔谴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一桩撮、第九天 我趴在偏房一處隱蔽的房頂上張望敦第。 院中可真熱鬧,春花似錦距境、人聲如沸申尼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽师幕。三九已至,卻和暖如春诬滩,著一層夾襖步出監(jiān)牢的瞬間霹粥,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工疼鸟, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留后控,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓空镜,卻偏偏與公主長(zhǎng)得像浩淘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吴攒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容