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

通過(guò)編寫(xiě)的第二篇文章可以成功創(chuàng)建一個(gè)新項(xiàng)目,即直接利用以下語(yǔ)句創(chuàng)建:

//命令行創(chuàng)建項(xiàng)目:
react-native init AwesomeProject

創(chuàng)建成功后,剛?cè)腴T(mén)的我們主要關(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)用開(kāi)始運(yùn)行的時(shí)候,RCTRootView將會(huì)從以下的URL中加載應(yīng)用:(本地調(diào)試的時(shí)候是直接在本地服務(wù)器中的index.ios加載,發(fā)布時(shí)設(shè)置有所不同)
   重新調(diào)用了你在運(yùn)行這個(gè)App時(shí)打開(kāi)的終端窗口,它開(kāi)啟了一個(gè) packager 和 server 來(lái)處理上面的請(qǐng)求。
   在 Safari 中打開(kāi)那個(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視圖封裝到原生組件中。(用戶(hù)能看到的一切內(nèi)容都來(lái)源于這個(gè)RootView,所有的初始化工作也都在這個(gè)方法內(nèi)完成。)

解析:
通過(guò)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文件中,則是通過(guò)this.props.images調(diào)用上面定義的參數(shù)。
this為AppRegistry.registerComponent注冊(cè)的組件(下面會(huì)講到)

RCTRootView同樣提供了一個(gè)可讀寫(xiě)的屬性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ǔ)法的一些不合理、不嚴(yán)謹(jǐn)之處,減少一些怪異行為;
消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全;
提高編譯器效率,增加運(yùn)行速度;
為未來(lái)新版本的Javascript做好鋪墊。
*/

//導(dǎo)入一些必要的模塊
//React Native內(nèi)置的組件可以直接通過(guò)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';

//類(lèi),這是默認(rèn)的載入類(lèi),繼承自Component,Component類(lèi)(組件)似于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ù),用來(lái)渲染實(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類(lèi)
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)起來(lái),組件中有state與prop(狀態(tài)與屬性)。

屬性(props)是標(biāo)簽里面的屬性, 組件之前通過(guò)標(biāo)簽的屬性來(lái)傳遞數(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來(lái)變更,當(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)物車(chē)的component,會(huì)根據(jù)用戶(hù)在購(gòu)物車(chē)中添加的產(chǎn)品和產(chǎn)品數(shù)量,顯示不同的價(jià)格,那么“總價(jià)”這個(gè)狀態(tài),就應(yīng)該用state表示。


這篇文章利用了一個(gè)很簡(jiǎn)單的例子去具體解析了React Native的基本代碼,最主要想理解組件的概念,由此可以更好的去理解別人的代碼,,接下去為了更好的入門(mén),會(huì)繼續(xù)寫(xiě)兩篇文章分別介紹React Native用到的js基礎(chǔ)、react基礎(chǔ),以及介紹組件的生命周期。

正在寫(xiě)React Native的學(xué)習(xí)教程ing,是一邊研究一邊編寫(xiě)的,已有的成果如下:
1) React Native 簡(jiǎn)介與入門(mén)
2) React Native 環(huán)境搭建和創(chuàng)建項(xiàng)目(Mac)
3) React Native 開(kāi)發(fā)之IDE

  1. React Native 入門(mén)項(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容