React Native ios开发第一课
前言
本篇文章的作用在于帮助你快速上手使用React Native编写iOS应用。如果你现在还不太了解React Native是什么以及Facebook为什么要创建React Native,你可以先看看这篇博客。
阅读本文之前,我们假设你已经有过使用React创建网站的经验。如果你还是一个React新手,那么我们建议你从React的网站开始学习。
设置
使用React Native开发iOS应用需要OSX系统,Xcode,Homebrew,node,npm以及watchman,你也可以有选择的使用Flow。
在安装完这些依赖项目之后,你可以简单的使用两行命令来开启一个React Native项目:
- npm install -g react-native-cli
react-native-cli是用来开发React Native的命令行工具。你需要使用npm来安装它。上面这行代码将会帮助你在terminal中安装react-native命令。当然,你只需要运行一次这行代码。
- 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
会复制
initExample/SampleProject
中的内容到你命名的项目中,在本文中项目名称为AwsomeProject。这是一个简单的hello
world应用。你可以通过编辑index.os.js
来改变这个应用,然后使用cmd+R
在模拟器中查看变化。
伪造数据
在我们开始编写代码从Rotten Tomatoes网站抓取数据之前,我们先来伪造一些数据以便我们可以马上体验一下React Native。在Facebook我们一般会在JS文件的顶部声明常量,并在后面使用,但是随便你加在哪里都好。在index.ios.js
中添加以下代码:
var MOCKED_MOVIES_DATA = [
{title: 'Title', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
];
渲染一部电影
我们会渲染电影标题,年份以及电影海报略缩图。由于略缩图在React Native中是一个Image组件,我们需要将Imagei到React的依赖项中。
var {
AppRegistry,
Image,
StyleSheet,
Text,
View,
} = React;
现在我们修改render函数以便我们可以将上面渲染上面的数据而不仅仅是渲染一个hello world:
render: function() {
var movie = MOCKED_MOVIES_DATA[0];
return (
<View style={styles.container}>
<Text>{movie.title}</Text>
<Text>{movie.year}</Text>
<Image source={{uri: movie.posters.thumbnail}} />
</View>
);
}
按下cmd+R
你应该在”2015”上面看到”Title”。注意此时Image什么都不会渲染。这是因为我们还没有指定想要的宽度和高度。这需要通过styles属性来设置。在我们修改styles的同时我们还需要把那些不再会使用的样式删除:
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 53,
height: 81,
},
});
最后我们需要将样式运用在Image组件上。
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
按下cmd+R
你会发现图片已经渲染出来了。
添加其他样式
很好,我们现在已经把数据渲染出来了。现在我们来让我们的应用变得好看一些。我想把文字放在图片的右侧,同时让标题大一些并居中:
+---------------------------------+
|+-------++----------------------+|
|| || Title ||
|| Image || ||
|| || Year ||
|+-------++----------------------+|
+---------------------------------+
我们会添加另一个container,这是为了让我们的组件在外层的组件中垂直居中。
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
现在并没有多少变化,我们在文字外层添加了一个包裹容器并将其放在了图片后面(因为文字要在图片的右边)。现在我们来看看样式会变成什么样:
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
我们在这里使用弹性盒模型来布局,如果你不熟悉弹性盒模型,可以看看这个教程。
在上面的代码中,我们简单的添加了flexDirection:
来确保我们的main container是水平布局而不是垂直布局。
'row'
现在我们添加另一组样式:
rightContainer: {
flex: 1,
},
上面代码的意思是rightContainer会占据外层容器右边的空间,左边则是图片。如果没有看出效果,可以为rightContainer添加一个backgroundColor
属性,同时移除flex:
。你会看到外出容器的体积会变得劲量的小来适应子容器。
1
而文本的样式很直观:
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
继续按下cmd+R
来查看更新之后的视图:
抓取真实数据
从Rotten Tomatoes的API抓取数据和学习React Native并没有多少关系,所以你可以风轻云淡的跳过这一节。
将下面的常量放在文件的顶部来创建一个请求数据使用的REQUEST_URL:
var API_KEY = '7waqfqbprs7pajbz28mqf6vz';
var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json';
var PAGE_SIZE = 25;
var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE;
var REQUEST_URL = API_URL + PARAMS;
为我们的应用添加初始状态以便我们可以通过检查this.state.movies
来确定电影数据有没有被城管加载。当电影数据返回时,我们可以通过
===
nullthis.setState({movies:
来设置数据。将下面的代码添加到render函数之前:
moviesData})
getInitialState: function() {
return {
movies: null,
};
},
我们想要在组件完成加载后发送请求,componentDidMount
是React组件中的一个函数,它只会在组件加载完成之后被调用一次。
componentDidMount: function() {
this.fetchData();
},
现在添加组件中会用到的fetchData
函数。这个方法将负责处理数据抓取。你需要做的仅仅是在promise完成解析之后调用this.setState({movies:
,因为
data})setState
会触发重新渲染,而此时render函数会注意到this.state.movies
不再是null
。注意我们会在promise链的最后调用done()
–一定要确保调用done()
,否则错误信息可能会被忽略。
fetchData: function() {
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
movies: responseData.movies,
});
})
.done();
},
现在修改render函数来渲染一个loading视图,如果电影数据还没有返回的话,否则将渲染第一部电影:
render: function() {
if (!this.state.movies) {
return this.renderLoadingView();
}
var movie = this.state.movies[0];
return this.renderMovie(movie);
},
renderLoadingView: function() {
return (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
},
renderMovie: function(movie) {
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
},
现在按下cmd+R
,你应该已经看到了”Loading
movies…”,直到电影数据返回,接着页面就会渲染第一部从Rotten Tomatoes抓回来的电影:
ListView
现在我们来修改应用来将所有的数据渲染在一个ListView
组件种,而不是只渲染一部电影。
为什么使用ListView
要比把所有数据放在一个ScrollView
里面好呢?虽然React速度很快,但是渲染一个可能是无限长的列表依然可能很慢。ListView
会自动渲染视线之内的视图,而那些在屏幕之外的视图会被暂时移除。
第一件事:在文件的最上方添加ListView
:
var {
AppRegistry,
Image,
ListView,
StyleSheet,
Text,
View,
} = React;
现在修改render函数以便一旦我们的数据返回沃恩就可以在一个ListView里面渲染数据:
render: function() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
DataSource
是一个ListView
的接口,作用是决定那些行会被改变。
注意在这里使用dataSource
而不是this.state
。下一步我们需要在getInitialState
的返回对象上添加一个空的dataSource
,我们不能再使用this.state.movies
防止数据被存储两次。我们可以使用state的布尔值属性(this.state.loaded
)来判断数据抓取是否结束:
getInitialState: function() {
return {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
},
在这里我们还需要修改fetchData
方法来更新state:
fetchData: function() {
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
loaded: true,
});
})
.done();
},
最后,我们在styles
中为ListView
组件添加样式:
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
下面是最终的效果图:
接下来我们还可以通过添加导航,搜索,无线滚动加载等等来弯沉一个完整的应用。你可以查看[电影示例](Movies Example)来查看完整的代码。
完整的源码
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
'use strict';
var React = require('react-native');
var {
AppRegistry,
Image,
ListView,
StyleSheet,
Text,
View,
} = React;
var API_KEY = '7waqfqbprs7pajbz28mqf6vz';
var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json';
var PAGE_SIZE = 25;
var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE;
var REQUEST_URL = API_URL + PARAMS;
var AwesomeProject = React.createClass({
getInitialState: function() {
return {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
},
componentDidMount: function() {
this.fetchData();
},
fetchData: function() {
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.movies),
loaded: true,
});
})
.done();
},
render: function() {
if (!this.state.loaded) {
return this.renderLoadingView();
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
},
renderLoadingView: function() {
return (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
},
renderMovie: function(movie) {
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
},
});
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
rightContainer: {
flex: 1,
},
title: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
React Native ios开发第一课的更多相关文章
- react native ios 开发,基础配置笔记。
一.获取硬件信息,使用react-native-device-info插件,配置说明: 1.首先需要安装组件:npm install react-native-device-info --save 2 ...
- React Native IOS ---基础环境搭建(前端架构师)
React Native -IOS 开发环境搭建 web架构(基础) 安装依赖 * 必须安装的依赖有:Node.Watchman 和 React Native 命令行工具以及 Xcode. npm 镜 ...
- 一、React Native 搭建开发环境(1)(Mac OS - IOS项目篇)
React Native是Facebook推出的一个开发IOS和安卓APP的技术.至于更多的详情,这里不再描述,大家可以自行百度它的定义. 原因:由于我想在一台电脑上同时开发IOS和Android两个 ...
- taro之React Native 端开发研究
初步结论:如果想把 React Native 集成到现有的原生项目中,不能使用taro的React Native 端开发功能(目前来说不能实现,以后再观察). RN开发有2种模式: 1.一是原生A ...
- React Native 混合开发与实现
关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 前言 随着 React 的盛行,其移动开发框架 React Native 也收到了广大开发者的青睐,以下简 ...
- react-native —— 在Windows下搭建React Native Android开发环境
在Windows下搭建React Native Android开发环境 前段时间在开发者头条收藏了 @天地之灵_邓鋆 分享的<在Windows下搭建React Native Android开发环 ...
- React Native iOS环境搭建
前段时间React Native for Android发布,感觉React Native会越来越多的公司开始研究.使用.所以周六也抽空搭建了iOS的开发环境,以便以后利用空闲的时间能够学习一下. 废 ...
- react-native —— 在Mac上配置React Native Android开发环境排坑总结
配置React Native Android开发环境总结 1.卸载Android Studio,在终端(terminal)执行以下命令: rm -Rf /Applications/Android\ S ...
- Expo大作战(三)--针对已经开发过react native项目开发人员有针对性的介绍了expo,expo的局限性,开发时项目选型注意点等
简要:本系列文章讲会对expo进行全面的介绍,本人从2017年6月份接触expo以来,对expo的研究断断续续,一路走来将近10个月,废话不多说,接下来你看到内容,讲全部来与官网 我猜去全部机翻+个人 ...
随机推荐
- JUnit单元测试教程(翻译自Java Code Geeks)
JUnit单元测试教程--终极指南 JUnit单元测试教程终极指南 说明 单元测试简介 1 什么是单元测试 2 测试覆盖 3 Java中的单元测试 JUnit简介 1 使用Eclipse实现简单JUn ...
- 【伯乐在线】这些 Git 技能够你用一年了
原文出处: Pyper 欢迎分享原创到伯乐头条 用git有一年了,下面是我这一年来的git使用总结,覆盖了日常使用中绝大多数的场景.嗯,至少是够用一年了,整理出来分享给大家,不明白的地方可以回复交 ...
- Spark核心类:SQLContext和DataFrame
http://blog.csdn.net/pipisorry/article/details/53320669 pyspark.sql.SQLContext Main entry point for ...
- 网卡配置和DNS配置,手动挂在nas存储的共享目录,网络相关其它操作命令,修改防火墙中的端口配置,resolv.conf配置详细介绍和网卡信息配置详细介绍
1. 网卡配置和DNS配置 若想服务器能够发邮件,需要让部署的服务器能够访问到外网环境.若部署的服务器访问不到外网,通过ping www.baidu.com的方式执行的时候,会出现以下问题: &q ...
- Android Multimedia框架总结(二十二)MediaCodec中C++中创建到start过程及状态变换
上一章介绍MediaCodec中创建到start过程(到jni部分),从今天开始,将深入源码中看看其c++过程,看下Agenda如下: mediacodec.h CreateByType initMe ...
- ROS(indigo)RRT路径规划
源码地址:https://github.com/nalin1096/path_planning 路径规划 使用ROS实现了基于RRT路径规划算法. 发行版 - indigo 算法在有一个障碍的环境找到 ...
- C++语言编译系统提供的内部数据类型的自动隐式转换
C++语言编译系统提供的内部数据类型的自动隐式转换规则如下: 程序在执行算术运算时,低类型自动隐式转换为高类型. 在函数调用时,将实参值赋给形参,系统隐式的将实参转换为形参的类型,并赋值给形参. 函数 ...
- Spark Scheduler模块源码分析之DAGScheduler
本文主要结合Spark-1.6.0的源码,对Spark中任务调度模块的执行过程进行分析.Spark Application在遇到Action操作时才会真正的提交任务并进行计算.这时Spark会根据Ac ...
- python 如何优雅地退出子进程
python 如何优雅地退出子进程 主进程产生子进程,子进程进入永久循环模式.当主进程要求子进程退出时,如何能安全地退出子进程呢? 参考一些代码,我写了这个例子.运行之后,用kill pid试试.pi ...
- JDBC存储和读取二进制数据
以下JSP文件用common-fileupload组件实现文件上传,并将文件以二进制文件的形式存入数据库 <% if("POST".equalsIgnoreCase(requ ...