React Native入门项目与解析-阿里云开发者社区

开发者社区> 开发与运维> 正文
登录阅读全文

React Native入门项目与解析

简介:

通过React Native 环境搭建和创建项目(Mac)可以成功创建一个新项目,即直接利用以下语句创建:


  1. //命令行创建项目: 
  2.  
  3. react-native init AwesomeProject 

创建成功后,刚入门的我们主要关注两个文件:

1)iOS项目目录下的AppDelegate.m

为将iOS项目连接js文件的入口,以及相关初始化操作。

2)根目录下的index.ios.js

为iOS对应的js入口文件。

一、 解析iOS项目中的AppDelegate.m

1. AppDelegate.m 代码如下:


  1. #import "AppDelegate.h" 
  2.  
  3. // React Native相关头文件 
  4.  
  5. #import "RCTBundleURLProvider.h" 
  6.  
  7. #import "RCTRootView.h" 
  8.  
  9. @implementation AppDelegate 
  10.  
  11. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
  12.  
  13.  
  14. NSURL *jsCodeLocation; 
  15.  
  16. /* 
  17.  
  18. 当应用开始运行的时候,RCTRootView将会从以下的URL中加载应用:(本地调试的时候是直接在本地服务器中的index.ios加载,发布时设置有所不同) 
  19.  
  20. 重新调用了你在运行这个App时打开的终端窗口,它开启了一个 packager 和 server 来处理上面的请求。 
  21.  
  22. 在 Safari 中打开那个 URL;你将会看到这个 App 的 JavaScript 代码 
  23.  
  24. */ 
  25.  
  26. [[RCTBundleURLProvider sharedSettings] setDefaults]; 
  27.  
  28. jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 
  29.  
  30. // RCTRootView是一个UIView容器,承载着React Native应用。同时它也提供了一个联通原生端和被托管端的接口。 
  31.  
  32. RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 
  33.  
  34. moduleName:@"AwesomeProject" 
  35.  
  36. initialProperties:nil 
  37.  
  38. launchOptions:launchOptions]; 
  39.  
  40. rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 
  41.  
  42. self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 
  43.  
  44. UIViewController *rootViewController = [UIViewController new]; 
  45.  
  46. rootViewController.view = rootView; 
  47.  
  48. self.window.rootViewController = rootViewController; 
  49.  
  50. [self.window makeKeyAndVisible]; 
  51.  
  52. return YES; 
  53.  
  54.  
  55. @end 

2. RCTRootView

RCTRootView将React Natvie视图封装到原生组件中。(用户能看到的一切内容都来源于这个RootView,所有的初始化工作也都在这个方法内完成。)

解析:

通过RCTRootView的初始化函数你可以将任意属性传递给React Native应用。

参数initialProperties必须是NSDictionary的一个实例。

这一字典参数会在内部被转化为一个可供JS组件调用的JSON对象。


  1. NSArray *imageList = @[@"http://foo.com/bar1.png"
  2.  
  3. @"http://foo.com/bar2.png"]; 
  4.  
  5. NSDictionary *propsDict = @{@"images" : imageList}; 
  6.  
  7. RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 
  8.  
  9. moduleName:@"AwesomeProject" 
  10.  
  11. initialProperties: propsDict 
  12.  
  13. launchOptions:launchOptions]; 

在js文件中,则是通过this.props.images调用上面定义的参数。

this为AppRegistry.registerComponent注册的组件(下面会讲到)

RCTRootView同样提供了一个可读写的属性appProperties。在appProperties设置之后,React Native应用将会根据新的属性重新渲染。当然,只有在新属性和之前的属性有区别时更新才会被触发。

(注意:1.可以随时更新属性,但是更新必须在主线程中进行,读取则可以在任何线程中进行。2.更新属性时并不能做到只更新一部分属性)


  1. NSArray *imageList = @[@"http://foo.com/bar3.png"
  2.  
  3. @"http://foo.com/bar4.png"]; 
  4.  
  5. rootView.appProperties = @{@"images" : imageList}; 

二、解析js入口文件(index.ios.js)

1. index.ios.js 代码如下:


  1. 'use strict'; // 全局进入严格模式(目前发现不用也行) 
  2.  
  3. /**< 
  4.  
  5. 消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为; 
  6.  
  7. 消除代码运行的一些不安全之处,保证代码运行的安全; 
  8.  
  9. 提高编译器效率,增加运行速度; 
  10.  
  11. 为未来新版本的Javascript做好铺垫。 
  12.  
  13. */ 
  14.  
  15. //导入一些必要的模块 
  16.  
  17. //React Native内置的组件可以直接通过import { xxx } from 'react-native' 进行导入,当然也可以自定义组件。 
  18.  
  19. import React, { Component } from 'react'
  20.  
  21. import { 
  22.  
  23. AppRegistry, 
  24.  
  25. StyleSheet, 
  26.  
  27. Text, 
  28.  
  29. View
  30.  
  31. TouchableOpacity 
  32.  
  33. from 'react-native'
  34.  
  35. //类,这是默认的载入类,继承自Component,Component类(组件)似于Android和iOS中的View 
  36.  
  37. //这里为创建一个组件 
  38.  
  39. class AwesomeProject extends Component { 
  40.  
  41. //构造器 ,每个组件都拥有自己的属性(props)和状态(state) 
  42.  
  43. //调用this.setState更改状态text或者isTouchDown时,组件会触发render函数进行渲染更新 
  44.  
  45. constructor(props) { 
  46.  
  47. super(props); 
  48.  
  49. this.state = { 
  50.  
  51. text:'Welcome to React Native!'
  52.  
  53. isTouchDown:false 
  54.  
  55. }; 
  56.  
  57.  
  58. //在最初的渲染之前调用一次,可在里面进行预处理操作 
  59.  
  60. //在React中,设置this.state会导致重新渲染,但是componentWillMount设置this.state并不会对导致render调用多次 
  61.  
  62. //之后会对component的生命周期进一步解释 
  63.  
  64. componentWillMount() { 
  65.  
  66.  
  67. //渲染函数,用来渲染实际的Component可视部分 
  68.  
  69. render() { 
  70.  
  71. //var定义变量,根据状态值改变对应值 
  72.  
  73. var welcomeText = this.state.text; 
  74.  
  75. var bgcolor; 
  76.  
  77. if (this.state.isTouchDown) { 
  78.  
  79. bgcolor = '#c5c5ab'
  80.  
  81. else { 
  82.  
  83. bgcolor = '#F5FCFF'
  84.  
  85.  
  86. console.log('testtststststts'); 
  87.  
  88. //返回的即界面显示内容 
  89.  
  90. return ( 
  91.  
  92. <View style={[styles.container, {backgroundColor: bgcolor}]}> 
  93.  
  94. <Text style={styles.welcome}> 
  95.  
  96. {welcomeText} 
  97.  
  98. </Text> 
  99.  
  100. <Text style={styles.instructions}> 
  101.  
  102. To get started, edit index.android.js 
  103.  
  104. </Text> 
  105.  
  106. <Text style={styles.instructions}> 
  107.  
  108. Shake or press menu button for dev menu 
  109.  
  110. </Text> 
  111.  
  112. <TouchableOpacity onPress={this.touchDown.bind(this)}> 
  113.  
  114. <Text style={[styles.instructions, {backgroundColor: 'green'}]}> 
  115.  
  116. test touch Me 
  117.  
  118. </Text> 
  119.  
  120. </TouchableOpacity> 
  121.  
  122. </View
  123.  
  124. ); 
  125.  
  126.  
  127. // 自定义函数 
  128.  
  129. touchDown() { 
  130.  
  131. // console.log 控制台打印,可打印值,多用于调试 
  132.  
  133. console.log('>>', this.isTouchDown); 
  134.  
  135. if (!this.state.isTouchDown) { 
  136.  
  137. this.setState({ 
  138.  
  139. text:'Test Touch Down Success'
  140.  
  141. isTouchDown:true 
  142.  
  143. }); 
  144.  
  145. else { 
  146.  
  147. this.setState({ 
  148.  
  149. text:'Test Touch Down Again Success'
  150.  
  151. isTouchDown:false 
  152.  
  153. }); 
  154.  
  155.  
  156.  
  157.  
  158. //定义样式 
  159.  
  160. const styles = StyleSheet.create({ 
  161.  
  162. container: { 
  163.  
  164. flex: 1, 
  165.  
  166. justifyContent: 'center'
  167.  
  168. alignItems: 'center'
  169.  
  170. backgroundColor: '#F5FCFF'
  171.  
  172. }, 
  173.  
  174. welcome: { 
  175.  
  176. fontSize: 20, 
  177.  
  178. textAlign: 'center'
  179.  
  180. margin: 10, 
  181.  
  182. }, 
  183.  
  184. instructions: { 
  185.  
  186. textAlign: 'center'
  187.  
  188. color: '#333333'
  189.  
  190. marginBottom: 5, 
  191.  
  192. }, 
  193.  
  194. }); 
  195.  
  196. //AppRegistry 定义了App的入口,并提供了根组件。 
  197.  
  198. //第一个'AwesomeProject'要与AppDelegate里注册的moduleName一致 
  199.  
  200. //第二个AwesomeProject则是入口组件,即上面定义的Component类 
  201.  
  202. AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject); 

2. 运行效果:

简单运行效果.png

3. 基础概念解释

1)组件

代码中的 Text, View, TouchableOpacity均为基础组件。AwesomeProject则是自己创建的组件,也作为项目的入口组件。

在React Native项目中,所有展示的界面,都可以看做是一个组件(Component)只是功能和逻辑上的复杂程度不同。每一个是许许多多小的组件拼成的,每个小的组件也有自己对应的逻辑。

2)组件的状态与属性

组件本质上是状态机,输入确定,输出一定确定。组件把状态与结果一一对应起来,组件中有state与prop(状态与属性)。

属性(props)是标签里面的属性, 组件之前通过标签的属性来传递数据,由父组件传递给子组件(单向的属性传递)。

如果component的某些状态由外部所决定,并且会影响到component的render,那么这些状态就应该用props表示。

例如:一个下拉菜单的component,有哪些菜单项,是由这个component的使用者和使用场景决定的,那么“菜单项”这个状态,就应该用props表示,并且由外部传入。

状态(state)是子组中的状态,内部的事件方法或者生命周期方法都可以调用this.setState来变更,当状态发生变化的同时,组件也会触发render函数进行渲染更新。

如果component的某些状态需要被改变,并且会影响到component的render,那么这些状态就应该用state表示。

例如:一个购物车的component,会根据用户在购物车中添加的产品和产品数量,显示不同的价格,那么“总价”这个状态,就应该用state表示。




作者:朱源浩
来源:51CTO

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享: