前言

本篇文章的作用在于帮助你快速上手使用React Native编写iOS应用。如果你现在还不太了解React Native是什么以及Facebook为什么要创建React Native,你可以先看看这篇博客

阅读本文之前,我们假设你已经有过使用React创建网站的经验。如果你还是一个React新手,那么我们建议你从React的网站开始学习。

设置

使用React Native开发iOS应用需要OSX系统,Xcode,Homebrew,node,npm以及watchman,你也可以有选择的使用Flow。

在安装完这些依赖项目之后,你可以简单的使用两行命令来开启一个React Native项目:

  1. npm install -g react-native-cli

react-native-cli是用来开发React Native的命令行工具。你需要使用npm来安装它。上面这行代码将会帮助你在terminal中安装react-native命令。当然,你只需要运行一次这行代码。

  1. react-native init AwsomeProject

这行代码可以获取所有React Native的源码以及依赖项,同时会创建一个叫做AwsomeProject/AwsomeProject.xcodeproj的全新Xcode项目。

开发

现在你可以在Xcode中开发这个新项目(AwsomeProject/AwsomeProject.xcodeproj),并简单的使用cmd+R来运行它。运行代码的同时也会自动开启一个node服务器来实现代码的热重载。这样一来你就可以通过cmd+R来查看变化而不需要每次都在Xcode中进行重编译。

在本文中我们将创建一个简单的电影应用,这个应用将抓取目前正在上映的最新的25部电影,并将它们展示在一个ListView中。

Hello World

react-native
init
会复制Example/SampleProject中的内容到你命名的项目中,在本文中项目名称为AwsomeProject。这是一个简单的hello
world应用。你可以通过编辑index.os.js来改变这个应用,然后使用cmd+R在模拟器中查看变化。

伪造数据

在我们开始编写代码从Rotten Tomatoes网站抓取数据之前,我们先来伪造一些数据以便我们可以马上体验一下React Native。在Facebook我们一般会在JS文件的顶部声明常量,并在后面使用,但是随便你加在哪里都好。在index.ios.js中添加以下代码:

  1. var MOCKED_MOVIES_DATA = [
  2. {title: 'Title', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
  3. ];

渲染一部电影

我们会渲染电影标题,年份以及电影海报略缩图。由于略缩图在React Native中是一个Image组件,我们需要将Imagei到React的依赖项中。

  1. var {
  2. AppRegistry,
  3. Image,
  4. StyleSheet,
  5. Text,
  6. View,
  7. } = React;

现在我们修改render函数以便我们可以将上面渲染上面的数据而不仅仅是渲染一个hello world:

  1. render: function() {
  2. var movie = MOCKED_MOVIES_DATA[0];
  3. return (
  4. <View style={styles.container}>
  5. <Text>{movie.title}</Text>
  6. <Text>{movie.year}</Text>
  7. <Image source={{uri: movie.posters.thumbnail}} />
  8. </View>
  9. );
  10. }

按下cmd+R你应该在”2015”上面看到”Title”。注意此时Image什么都不会渲染。这是因为我们还没有指定想要的宽度和高度。这需要通过styles属性来设置。在我们修改styles的同时我们还需要把那些不再会使用的样式删除:

  1. var styles = StyleSheet.create({
  2. container: {
  3. flex: 1,
  4. justifyContent: 'center',
  5. alignItems: 'center',
  6. backgroundColor: '#F5FCFF',
  7. },
  8. thumbnail: {
  9. width: 53,
  10. height: 81,
  11. },
  12. });

最后我们需要将样式运用在Image组件上。

  1. <Image
  2. source={{uri: movie.posters.thumbnail}}
  3. style={styles.thumbnail}
  4. />

按下cmd+R你会发现图片已经渲染出来了。

添加其他样式

很好,我们现在已经把数据渲染出来了。现在我们来让我们的应用变得好看一些。我想把文字放在图片的右侧,同时让标题大一些并居中:

  1. +---------------------------------+
  2. |+-------++----------------------+|
  3. || || Title ||
  4. || Image || ||
  5. || || Year ||
  6. |+-------++----------------------+|
  7. +---------------------------------+

我们会添加另一个container,这是为了让我们的组件在外层的组件中垂直居中。

  1. return (
  2. <View style={styles.container}>
  3. <Image
  4. source={{uri: movie.posters.thumbnail}}
  5. style={styles.thumbnail}
  6. />
  7. <View style={styles.rightContainer}>
  8. <Text style={styles.title}>{movie.title}</Text>
  9. <Text style={styles.year}>{movie.year}</Text>
  10. </View>
  11. </View>
  12. );

现在并没有多少变化,我们在文字外层添加了一个包裹容器并将其放在了图片后面(因为文字要在图片的右边)。现在我们来看看样式会变成什么样:

  1. container: {
  2. flex: 1,
  3. flexDirection: 'row',
  4. justifyContent: 'center',
  5. alignItems: 'center',
  6. backgroundColor: '#F5FCFF',
  7. },

我们在这里使用弹性盒模型来布局,如果你不熟悉弹性盒模型,可以看看这个教程

在上面的代码中,我们简单的添加了flexDirection:
'row'
来确保我们的main container是水平布局而不是垂直布局。

现在我们添加另一组样式:

  1. rightContainer: {
  2. flex: 1,
  3. },

上面代码的意思是rightContainer会占据外层容器右边的空间,左边则是图片。如果没有看出效果,可以为rightContainer添加一个backgroundColor属性,同时移除flex:
1
。你会看到外出容器的体积会变得劲量的小来适应子容器。

而文本的样式很直观:

  1. title: {
  2. fontSize: 20,
  3. marginBottom: 8,
  4. textAlign: 'center',
  5. },
  6. year: {
  7. textAlign: 'center',
  8. },

继续按下cmd+R来查看更新之后的视图:

抓取真实数据

从Rotten Tomatoes的API抓取数据和学习React Native并没有多少关系,所以你可以风轻云淡的跳过这一节。

将下面的常量放在文件的顶部来创建一个请求数据使用的REQUEST_URL:

  1. var API_KEY = '7waqfqbprs7pajbz28mqf6vz';
  2. var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json';
  3. var PAGE_SIZE = 25;
  4. var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE;
  5. var REQUEST_URL = API_URL + PARAMS;

为我们的应用添加初始状态以便我们可以通过检查this.state.movies
===
null
来确定电影数据有没有被城管加载。当电影数据返回时,我们可以通过this.setState({movies:
moviesData})
来设置数据。将下面的代码添加到render函数之前:

  1. getInitialState: function() {
  2. return {
  3. movies: null,
  4. };
  5. },

我们想要在组件完成加载后发送请求,componentDidMount是React组件中的一个函数,它只会在组件加载完成之后被调用一次。

  1. componentDidMount: function() {
  2. this.fetchData();
  3. },

现在添加组件中会用到的fetchData函数。这个方法将负责处理数据抓取。你需要做的仅仅是在promise完成解析之后调用this.setState({movies:
data})
,因为setState会触发重新渲染,而此时render函数会注意到this.state.movies不再是null。注意我们会在promise链的最后调用done()–一定要确保调用done(),否则错误信息可能会被忽略。

  1. fetchData: function() {
  2. fetch(REQUEST_URL)
  3. .then((response) => response.json())
  4. .then((responseData) => {
  5. this.setState({
  6. movies: responseData.movies,
  7. });
  8. })
  9. .done();
  10. },

现在修改render函数来渲染一个loading视图,如果电影数据还没有返回的话,否则将渲染第一部电影:

  1. render: function() {
  2. if (!this.state.movies) {
  3. return this.renderLoadingView();
  4. }
  5. var movie = this.state.movies[0];
  6. return this.renderMovie(movie);
  7. },
  8. renderLoadingView: function() {
  9. return (
  10. <View style={styles.container}>
  11. <Text>
  12. Loading movies...
  13. </Text>
  14. </View>
  15. );
  16. },
  17. renderMovie: function(movie) {
  18. return (
  19. <View style={styles.container}>
  20. <Image
  21. source={{uri: movie.posters.thumbnail}}
  22. style={styles.thumbnail}
  23. />
  24. <View style={styles.rightContainer}>
  25. <Text style={styles.title}>{movie.title}</Text>
  26. <Text style={styles.year}>{movie.year}</Text>
  27. </View>
  28. </View>
  29. );
  30. },

现在按下cmd+R,你应该已经看到了”Loading
movies…”,直到电影数据返回,接着页面就会渲染第一部从Rotten Tomatoes抓回来的电影:

ListView

现在我们来修改应用来将所有的数据渲染在一个ListView组件种,而不是只渲染一部电影。

为什么使用ListView要比把所有数据放在一个ScrollView里面好呢?虽然React速度很快,但是渲染一个可能是无限长的列表依然可能很慢。ListView会自动渲染视线之内的视图,而那些在屏幕之外的视图会被暂时移除。

第一件事:在文件的最上方添加ListView

  1. var {
  2. AppRegistry,
  3. Image,
  4. ListView,
  5. StyleSheet,
  6. Text,
  7. View,
  8. } = React;

现在修改render函数以便一旦我们的数据返回沃恩就可以在一个ListView里面渲染数据:

  1. render: function() {
  2. if (!this.state.loaded) {
  3. return this.renderLoadingView();
  4. }
  5. return (
  6. <ListView
  7. dataSource={this.state.dataSource}
  8. renderRow={this.renderMovie}
  9. style={styles.listView}
  10. />
  11. );
  12. }

DataSource是一个ListView的接口,作用是决定那些行会被改变。

注意在这里使用dataSource而不是this.state。下一步我们需要在getInitialState的返回对象上添加一个空的dataSource,我们不能再使用this.state.movies防止数据被存储两次。我们可以使用state的布尔值属性(this.state.loaded)来判断数据抓取是否结束:

  1. getInitialState: function() {
  2. return {
  3. dataSource: new ListView.DataSource({
  4. rowHasChanged: (row1, row2) => row1 !== row2,
  5. }),
  6. loaded: false,
  7. };
  8. },

在这里我们还需要修改fetchData方法来更新state:

  1. fetchData: function() {
  2. fetch(REQUEST_URL)
  3. .then((response) => response.json())
  4. .then((responseData) => {
  5. this.setState({
  6. dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
  7. loaded: true,
  8. });
  9. })
  10. .done();
  11. },

最后,我们在styles中为ListView组件添加样式:

  1. listView: {
  2. paddingTop: 20,
  3. backgroundColor: '#F5FCFF',
  4. },

下面是最终的效果图:

接下来我们还可以通过添加导航,搜索,无线滚动加载等等来弯沉一个完整的应用。你可以查看[电影示例](Movies Example)来查看完整的代码。

完整的源码

  1. /**
  2. * Sample React Native App
  3. * https://github.com/facebook/react-native
  4. */
  5. 'use strict';
  6. var React = require('react-native');
  7. var {
  8. AppRegistry,
  9. Image,
  10. ListView,
  11. StyleSheet,
  12. Text,
  13. View,
  14. } = React;
  15. var API_KEY = '7waqfqbprs7pajbz28mqf6vz';
  16. var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json';
  17. var PAGE_SIZE = 25;
  18. var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE;
  19. var REQUEST_URL = API_URL + PARAMS;
  20. var AwesomeProject = React.createClass({
  21. getInitialState: function() {
  22. return {
  23. dataSource: new ListView.DataSource({
  24. rowHasChanged: (row1, row2) => row1 !== row2,
  25. }),
  26. loaded: false,
  27. };
  28. },
  29. componentDidMount: function() {
  30. this.fetchData();
  31. },
  32. fetchData: function() {
  33. fetch(REQUEST_URL)
  34. .then((response) => response.json())
  35. .then((responseData) => {
  36. this.setState({
  37. dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
  38. loaded: true,
  39. });
  40. })
  41. .done();
  42. },
  43. render: function() {
  44. if (!this.state.loaded) {
  45. return this.renderLoadingView();
  46. }
  47. return (
  48. <ListView
  49. dataSource={this.state.dataSource}
  50. renderRow={this.renderMovie}
  51. style={styles.listView}
  52. />
  53. );
  54. },
  55. renderLoadingView: function() {
  56. return (
  57. <View style={styles.container}>
  58. <Text>
  59. Loading movies...
  60. </Text>
  61. </View>
  62. );
  63. },
  64. renderMovie: function(movie) {
  65. return (
  66. <View style={styles.container}>
  67. <Image
  68. source={{uri: movie.posters.thumbnail}}
  69. style={styles.thumbnail}
  70. />
  71. <View style={styles.rightContainer}>
  72. <Text style={styles.title}>{movie.title}</Text>
  73. <Text style={styles.year}>{movie.year}</Text>
  74. </View>
  75. </View>
  76. );
  77. },
  78. });
  79. var styles = StyleSheet.create({
  80. container: {
  81. flex: 1,
  82. flexDirection: 'row',
  83. justifyContent: 'center',
  84. alignItems: 'center',
  85. backgroundColor: '#F5FCFF',
  86. },
  87. rightContainer: {
  88. flex: 1,
  89. },
  90. title: {
  91. fontSize: 20,
  92. marginBottom: 8,
  93. textAlign: 'center',
  94. },
  95. year: {
  96. textAlign: 'center',
  97. },
  98. thumbnail: {
  99. width: 53,
  100. height: 81,
  101. },
  102. listView: {
  103. paddingTop: 20,
  104. backgroundColor: '#F5FCFF',
  105. },
  106. });
  107. AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);


React Native ios开发第一课的更多相关文章

  1. react native ios 开发,基础配置笔记。

    一.获取硬件信息,使用react-native-device-info插件,配置说明: 1.首先需要安装组件:npm install react-native-device-info --save 2 ...

  2. React Native IOS ---基础环境搭建(前端架构师)

    React Native -IOS 开发环境搭建 web架构(基础) 安装依赖 * 必须安装的依赖有:Node.Watchman 和 React Native 命令行工具以及 Xcode. npm 镜 ...

  3. 一、React Native 搭建开发环境(1)(Mac OS - IOS项目篇)

    React Native是Facebook推出的一个开发IOS和安卓APP的技术.至于更多的详情,这里不再描述,大家可以自行百度它的定义. 原因:由于我想在一台电脑上同时开发IOS和Android两个 ...

  4. taro之React Native 端开发研究

    初步结论:如果想把 React Native 集成到现有的原生项目中,不能使用taro的React Native 端开发功能(目前来说不能实现,以后再观察).   RN开发有2种模式: 1.一是原生A ...

  5. React Native 混合开发与实现

    关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 前言 随着 React 的盛行,其移动开发框架 React Native 也收到了广大开发者的青睐,以下简 ...

  6. react-native —— 在Windows下搭建React Native Android开发环境

    在Windows下搭建React Native Android开发环境 前段时间在开发者头条收藏了 @天地之灵_邓鋆 分享的<在Windows下搭建React Native Android开发环 ...

  7. React Native iOS环境搭建

    前段时间React Native for Android发布,感觉React Native会越来越多的公司开始研究.使用.所以周六也抽空搭建了iOS的开发环境,以便以后利用空闲的时间能够学习一下. 废 ...

  8. react-native —— 在Mac上配置React Native Android开发环境排坑总结

    配置React Native Android开发环境总结 1.卸载Android Studio,在终端(terminal)执行以下命令: rm -Rf /Applications/Android\ S ...

  9. Expo大作战(三)--针对已经开发过react native项目开发人员有针对性的介绍了expo,expo的局限性,开发时项目选型注意点等

    简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...

随机推荐

  1. Android等宽字体

    Android等宽字体 效果图 在xml中设置 添加属性 android:typeface="monospace" 例如 <TextView android:layout_w ...

  2. Android自定义异常类

    当一个项目中,异常可能出现地方非常多的时候就需要考虑封装处理异常信息.本篇博客就对自定义异常做一个封装,模拟实际开发中的异常处理. 新建一个基类异常HException: public class H ...

  3. 微信小程序基础之input输入框控件

    今天主要详写一下微信小程序中的Input输入框控件,输入框在程序中是最常见的,登录,注册,获取搜索框中的内容等等都需要,同时,还需要设置不同样式的输入框,今天的代码中都要相应的使用. input输入框 ...

  4. 【Java二十周年】Delphi转行java的一些小感触

    本文纯属一届小码农对java使用过程的体验感触 目录: 初遇java编程语言 与java的擦肩 深入java 跨平台性 开源支持 web的支撑 初遇java编程语言 刚上大学的时候,完全是个电脑盲.刚 ...

  5. (一三〇)UITextField的光标操作扩展

    简介 在iOS开发中,有时候需要完全自主的定义键盘,用于完整的单词输入,例如计算机应用中,需要一次性的输入sin(,在移动光标时要完整的跳过sin(,在删除时也要完整的删除,这就需要对光标的位置进行精 ...

  6. Java: How to resolve Access Restriction error

    Issue: Access restriction: The constructor 'BASE64Decoder()' is not API (restriction on required lib ...

  7. 早期Swift中Cocos2D初始化代码的重构

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在早期的Swift中在子类里只能调用超类的design ...

  8. 概率论:假设检验-t检验和Augmented Dickey–Fuller test

    http://blog.csdn.net/pipisorry/article/details/51184556 T检验 T检验,亦称student t检验(Student's t test),学生t检 ...

  9. Collections类解析

    最常用的排序: 需要实现Comparable接口 1.什么是Comparable接口 此接口强行对实现它的每个类的对象进行整体排序.此排序被称为该类的自然排序 ,类的 compareTo 方法被称为它 ...

  10. 01_Linux系统系统语言查询,设置Xshell工具,中文显示,测试Xshell中文字符显示,Linux中文显示乱码设置

              Xshell是一个强大的安全终端模拟软件,它支持SSH1,SSH2,以及Microsoft Windows平台的TELNETNetSarang Xshell 4 Build 0 ...