ToB企服应用市场:ToB评测及商务社交产业平台

标题: ReactNative IOS 开辟教程(一) [打印本页]

作者: 天津储鑫盛钢材现货供应商    时间: 2024-10-25 13:57
标题: ReactNative IOS 开辟教程(一)
原文:React native for iOS development
  协议:CC BY-NC-SA 4.0
  一、学习基础:React 的短停息顿之旅

“千里之行始于足下。”—老子
在开始 React Native 之旅之前,您必须对 React(也称为 ReactJS 或 React.js)有所了解。在本章中,您将快速了解 React 的焦点概念,这将有助于您使用 React Native。React 不同于大多数盛行的 web 技能,随着本章的深入,您将会了解其中的原因。如果你已经花了相当多的时间在传统框架上,它的焦点概念将会真正打开你的思维方式;这种新的思维方式偶然被称为 React 式思维方式。您大概听说过“一次编写,到处运行”这句话,但由于各种情势(web、移动设备、平板电脑)的激增,您以为这险些是不大概的。React 有一个不同的指导原则:“学习一次,在任何地方写作。”哇,那看起来很不一样,很自由。因此,您将从快速欣赏 React 开始第一章,这将帮助您为 React Native 做好准备。如果你对 React 有初步的了解,你可以跳过这一章,进入第二章。
React 是一个用于创建用户界面的 JavaScript 库。它是由脸书和 Instagram 团队共同积极打造的。React 于 2013 年初次向天下推出,并在社区范围内得到了广泛认可,并受益于作为脸书焦点技能的优势。根据官方文档,有些人以为 React Native 是 MVC 中的 V,因为 React Native 对所使用的其他技能栈没有任何假设。你可以使用任何你想要的技能,你可以用 React Native 创建你的应用的一个单独的部分;您也可以方便地在已经创建的应用中举行更改。
为什么要 React?

但是在一个充满 js 库和框架的天下里,我们还必要另一个 JavaScript 库吗?险些每个月都会引入新的 js 框架。
React 的出现是因为它的创造者面临着一个重大题目:怎样构建数据频繁变化的大型应用。这个题目险些出现在任何现实天下的应用中,React 就是为了办理这个题目而诞生的。众所周知,许多盛行的框架都是 MVC 或 MV框架,但这里有一点必要注意和重申:React 不是 MV框架。这只是一个为数据随时间变化的 UI 组件构建可组适用户界面的库。与盛行的 js 框架不同,React 不使用模板或 HTML 指令。React 通过将 UI 分成许多组件来构建用户界面。就如许,没别的了。这意味着 React 使用编程语言的全部功能来构建和出现视图。
以下是为您的下一个项目选择 React 的一些优势:

为了对一项新技能有一个坚实的基础,有必要了解它的焦点概念。在下一节中,您将探索 React 的一些独特概念,这将使您更进一步了解这项令人赞叹的技能。
虚拟 DOM

在全部 web 应用中,应用遭受的最昂贵的操纵之一是改变 DOM。为了办理这个题目,React 维护了一个 DOM 的虚拟表示(如图 1-1 所示),它被称为虚拟 DOM 或 VDOM。除了差分算法,React Native 还能够盘算实际 DOM 的增量,并只更新 DOM 中发生变化的部分。因此,更改的数目较少,这导致应用非常快。在应用的开始阶段,你大概看不到它,但是随着你的项目膨胀到疯狂的复杂程度(这通常发生在现实天下的应用中),你将开始看到用户快速体验的好处。

图 1-1。
Virtual DOM and diffing algorithm operations
手动 DOM 操纵很贫苦,并且很难跟踪 DOM 从前的状态。如图 1-1 所示,React 通过保留一个虚拟 DOM 的两个副本来办理这个题目。接下来,对这两个虚拟 DOM 应用一个不同的算法,该算法主要查抄发生的更改并返回 DOM 操纵流。这些 DOM 操纵然后被应用到实际的欣赏器 DOM。
现在让我们从组件的角度来明白虚拟 DOM 是怎样工作的。在 React 中,每个组件都有一个状态;这种状态是可以观察到的。每当状态发生变化时,React 根本上都知道这种变化必要重新渲染。所以当应用状态改变时,它会天生一个新的 VTreediff 算法再次共享了所需更改的 DOM 路径,如图 1-2 所示。这使得手动 DOM 操纵最少。

图 1-2。
Components with virtual DOM
虚拟 DOM 的这个特性不仅重要,而且是 React 的杀手锏。DOM 访问速率非常慢,谦善地说,在大多数应用中一次又一次地访问 DOM 使得情况变得更糟。为了让你的应用运行得更快,你应该尽大概少的打仗 DOM,而虚拟 DOM 的实现很好的处置惩罚了这一点。对于一个小而琐碎的应用,您不会注意到这一点,但是一旦您的应用增长到有数千个 DOM 元素都试图更新,React 将不会让您的性能受到影响。
单向数据流

React 主要是 MVC 模式中的 V,但是在深入 React 中单向数据流的概念之前,您必须明白 MVC 框架的挑战。MVC 框架的最大挑战之一是管理视图。如您所知,MVC 框架的视图组件主要是 DOM 表示。当您编写与 DOM 交互的代码时,这很简单,但是对于框架来说,处置惩罚各种 DOM 操纵黑白常复杂的。
传统的 MVC 视图通常包含许多繁重的 UI,当数据发生变化时,即使是很小的元素,终极也会重新出现应用,循环继承。这是因为通常大多数 MVC 框架都遵循双向数据绑定(见图 1-3 )。

图 1-3。
Two-way data binding
在 JavaScript 中,数据在内存中更改,并且绑定到 UI 中的一个视图,这意味着当在内存中的 JavaScript 中修改数据时,UI 中的数据也会更改。反过来,当 UI(即 DOM)中的数据通过单击按钮或任何其他变乱发生变化时,它也会在内存中得到更新,从而使二者保持同步。理论上,这是完善的,这个想法是浪漫的完善。然而,在现实天下的应用中,当您有一个相当复杂和大的应用,用多个视图表示您的一个模子中的数据时,题目就出现了。随着您添加更多的模子和更多的视图,这种双向数据绑定终极会像意大利面条一样,将数据的每次更改添加到锅里,偶然乃至会导致无穷变乱循环,其中一个视图更新一个模子,而模子又更新一个视图,以此类推,如图 1-4 所示。

图 1-4。
Unwanted spaghetti relationship
这个系统的另一个题目是做出改变的代价非常高。当你向一个新开辟职员先容一个云云复杂的应用时,很难懂白一个变化大概会在这种错综复杂的关系中造成的影响。
React 遵循单向数据流以保持简单,如图 1-5 所示。它基于关注点分离(SoC)的概念。这是盘算机科学中的一个设计原则,其中一个应用或程序被分成不同的部分,每个部分办理一个单独的或特定的题目。这种设计原则的代价在于,它简化了开辟,创建了可维护和可伸缩的应用。这导致了模块化的代码,其中一个单独的部分可以被独立地重用、开辟和修改。这很有意义,确实是聪明思维的一个例子。

图 1-5。
React Native’s one-way data flow
安装和设置

为了明白实际的例子,您必须起首设置您的环境来运行您的 React 例子。开始使用 React 最简单的方法是使用 JSFiddle 示例。

另一种方法是下载完整的初学者工具包乃至离线工作: http://facebook.github.io/react/downloads/react-0.13.3.zip
您也可以使用 npm: npm install -g react-tools安装 react-tools。
使用 React Native 提高工作效率的另一个有用工具是 React Developer Tools,这是一个非常有用的 Chrome 扩展,允许您在 Chrome 欣赏器中查抄 React 组件条理布局:
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
为了方便起见,您将在本章的示例中使用以下设置:React Native 和 JSX transformer 的脸书 cdn。
react . js:fb.me/react-0.13.3.js
JSX 变压器: http://fb.me/JSXTransformer-0.13.3.js
只需在代码中引用它们。接下来,您将安装节点包 browserify、watchify 和 babelify,这将帮助您转换 JSX 并将其保存在适当的 js 文件中:
s$ npm install react browserify watchify babelify --save-dev
$ watchify –t babelify ./your-jsx-file.jsx –o ./final-js-file.js –v
太好了!要为应用提供服务,您将通过以下命令在项目文件夹的根目录中使用简单的 python 服务器(SimpleHTTPServer ):
$ python -m SimpleHTTPServer
默认情况下,简单 python 服务器将在 8000 端口上为您的示例提供服务。
现在您已经完成了设置,您可以很快开始明白 React 的概念。
组件先容

React 是关于组件的。您在 React 中做的任何事情都是基于可重用组件的。换句话说,使用 React 你只做一件事,那就是构建组件。在前面的章节中,我们讨论了关注点的分离。这些组件的整个概念是它们被完全封装,使它们易于测试和重用。
创建可重用组件是一项艺术工作,React Native 为您提供了许多特性。您将很快深入研究它们,但是起首让我们创建一个简单的“Hello World”组件。
创建一个hello_world.html文件,并将以下代码粘贴到其中:
<!DOCTYPE html>
<html>
<head>
<script src="http://fb.me/react-0.13.3.js
<script src="http://fb.me/JSXTransformer-0.13.3.js
</head>
<body>
<div id="intro"></div>
<script type="text/jsx">
React.render(
<h1>Hello, world </h1>, document.getElementById('intro')
);
</script>
</body>
</html>
这很简单。您的代码驻留在 HTML 标记中。JavaScript 驻留在脚本标签中。我们确实在范例’text/jsx’中看到了一些不同的东西;这就是 JSX,我们将在接下来的章节中详细表明。我们还看到一个关键字“React ”,这是 React 库的入口点。其中有包含所需文本的 H1 标签,以及文本出现的目标(在本例中为document.getElementById(intro))。此外,这个 React 代码可以存在于一个单独的文件中,并且可以在 HTML 中被引用。让我们创建一个名为src/helloworld.js.的单独文件
React.render(
<h1>Hello, world </h1>,
document.getElementById(“intro”)
);
现在让我们在您的hello_world.html file:中引用它
<script type="text/jsx" src="src/hello-world.js"></script>
这很简单。但是什么是 JSX 呢?在我们全面了解组件的不同方面之前,让我们先来看看 JSX。
小艾

React 不要求您使用 JSX。然而,JSX 确实让生活变得更简单。其类似 XML 的语法有助于非常容易地界说带有属性的树布局。XML 有很多好处,比如平衡开放标签和封闭标签。这使得大树比函数调用或对象笔墨更容易阅读。
让我们看一个简单的例子,先不看 JSX,看看随着我们逐渐包括 JSX,事情是怎样变得简单的。
<!DOCTYPE HTML>
<html lang='en'>
<head>
<meta charset="UTF-8">
<title>Example without JSX</title>
<script src="http://fb.me/react-0.13.3.js
</head>
<body>
<script >
var Appo = React.createClass({
render:function(){
return React.createElement("h1",null, "Hello Dear")
}
});
React.render(React.createElement(Appo), document.body);
</script>
</body>
</html>
在本例中,您使用了React.createElement。您起首传递一个表示 HTML 标记的字符串,第二个是您的属性,第三个是子元素,在本例中是内部 HTML。
接下来,您盼望在React.render中出现您的组件,因此您传递应用组件,并将其作为document.body加载到目标位置。输出类似于图 1-6 。

图 1-6。
Output in React.render
接下来,我们再来看一个方法,这个方法已经被弃用,不再使用了。(React 生态系统发展云云之快,以至于有些东西已经被弃用了;然而,回顾一下过去,就会发现在云云短的时间内,他们在使事情变得更容易方面取得了多大的进展。)
<!DOCTYPE HTML>
<html lang='en'>
<head>
<meta charset="UTF-8">
<title>Old world example</title>
<script src="http://fb.me/react-0.13.3.js
</head>
<body>
<script>
var Appo = React.createClass({
render:function(){
return React.DOM.h1(null, "Hello Past")
}
});
React.render(Appo(), document.body);
</script>
</body>
</html>
这个例子使用了React.DOM模式,其中指定了要使用的标签(在这个例子中是 h1);第一个参数是属性,第二个是字符串,用作内部 HTML。当使用React.render出现时,您将组件函数和目标传递到它要被加载的地方(在本例中是文档体)。如果你有 React 的最新版本,你会在你的控制台得到如图 1-7 所示的告诫和错误。

图 1-7。
DevTools will show this warning
访问 http://fb.me/react-legacyfactory 找到除了 JSX 调用工厂之外的另一种方法,在调用组件之前包装组件。这也提醒你是时候使用 JSX 了。
现在让我们看看使用 JSX 时,同一个示例是什么样子的(另见图 1-8 ):

图 1-8。
Output using JSX
<!DOCTYPE HTML>
<html lang='en'>
<head>
<meta charset="UTF-8">
<title>JSX me like !</title>
<script src="http://fb.me/react-0.13.3.js
<script src="http://fb.me/JSXTransformer-0.13.3.js
</head>
<body>
<!-- with JSX -->
<script type="text/jsx">
var App = React.createClass({
render:function(){
return <h1>Hi from JSX</h1>
}
});
React.render(<App />, document.body);
</script>
</body>
</html>
在这里,我们已经包括 JSX 变压器,欣赏器内的变压器。你的组件应用有 h1 标签。接下来,您使用React.render出现它,以 JSX 语法传递您的组件,并将第二个参数作为目标,即document.body。就如许。
现在将您的 JSX 代码分离到一个单独的JSX文件中,并将其转换成纯 JavaScript,看看会发生什么。为此,让我们创建一个名为src的文件夹,并将您的 JSX 代码放入hello.jsx文件中:
var Appo = React.createClass({
render:function(){
return React.DOM.h1(null, "Hello Past")
}
});
React.render(Appo(), document.body);
接下来,让我们添加一个dist文件夹,您可以在其中保存转换后的 js 文件示例bundle.js。之后,在 HTML 文件中引用您的bundle.js文件(在本例中是jsx_example.html)。
如前所述,您应该安装节点包 browserify、babelify 和 watchify,以便使用它们将您的 JSX 转换成 js。这可以使用以下命令来完成:
$ npm install react browserify watchify babelify --save-dev
现在,用下面的命令将您的hello.jsx转换成bundle.js:
$ watchify –t babelify ./src/hello.jsx –o ./dist/bundle.js –v
结果是下面的bundle.js文件:
var Appo = React.createClass({
displayName: "Appo",
render: function render() {
return React.DOM.h1(null, "Hello Past");
}
});
React.render(Appo(), document.body);
只管 React 并不明确要求 JSX,但它是首选。它允许您使用 HTML 语法创建 JavaScript 对象。组件有两个用途:模板和表现逻辑。因此,标记和代码紧密地接洽在一起。表现逻辑通常非常复杂,使用模板语言来表达它确实变得很困难。办理这个题目标最好方法是从 JavaScript 本身天生 HTML 和组件。JSX 通过创建 React 树节点,用其 HTML 范例的语法办理了这些题目。
为了更好的可维护性,您可以保持 JSX 源代码的完整性;把它放在 JSX 档案的独立文件夹里。要将 JSX 代码转换成平常的 JavaScript,可以手动或通过构建脚本使用 JSX 编译器( http://facebook.github.io/react/jsx-compiler.html )。在您的生产环境中提供 JSX 文件是大概的,但是 React 将向您提供有关性能降低的控制台通知。
深入了解组件

在下一节中,您将探索组件的重要概念,这将帮助您轻松地使用它们。
性能

React 有些类似于 HTML 中的属性:properties。您可以使用它们来初始化您的组件,就像如许:
React.render(<App myProp="Hi from prop" />, document.getElementById('container'))
这里你用一个名为myProp的属性初始化 App 组件,这个属性的目标是'container'的 id。您可以通过以下方式在 JSX 通过插值访问此属性。让我们创建一个组件应用:
var App = React.createClass({
render: function(){
var txt = this.props.txt
return (
<div>
<h1> {myProp} </h1>
</div>
);
}
});
React.render(<App myProp="Hi from prop" />, document.getElementById('container'))
如果刷新欣赏器,您将看到来自内部 HTML 的属性的消息。请为您的 HTML 文件使用以下代码(结果如图 1-9 所示):

图 1-9。
Refreshing your browser produces this message
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div id="container"></div>
</body>
<script src="http://fb.me/react-0.13.3.js
<script src="http://fb.me/JSXTransformer-0.13.3.js
<script src="dist/bundle.js"></script>
</html>
随着应用的增长,您起首必要确保组件是精确创建的。对于属性,您可以用一系列验证器来指定一种属性。这确保并验证了接收到的数据范例。让我们用一个例子来看看其中的一些:
var App = React.createClass({
propTypes: {
message: React.PropTypes.string,
age: React.PropTypes.number
},
render: function(){
// keeping props in a variable to use to often
var message = this.props.message,
age = this.props.age
return (
<div>
<h1> {message} </h1>
<p> My age is {age}</p>
</div>
);
}
});
React.render(<App age={5} message="Hi from prop" />, document.getElementById('container'))
这里,propType关键字表示属性名及其范例的散列。在您的示例中有两个 prop type:string和number,分别对应于message和age属性。
另有许多其他的财产范例。请注意,您可以将isRequired添加到任何 propType 的末尾,使其成为必需的:
propTypes: {
//some specific JS primitive
arrayType: React.PropTypes.array,
boolType: React.PropTypes.bool,
funcType: React.PropTypes.func,
objectType: React.PropTypes.object,
//if a value of a prop is necessary
numberType: React.PropTypes.number.isRequired
}
通过关键字getDefaultProps在属性中也有一个默认范例。例如,在同一个组件中,您可以为您的message和age属性指定默认范例:
getDefaultProps: function(){
return {
message: 'Default value of message',
age: 0
}
},
状态

在上一节中,您了解了属性,这些属性是传递到组件中的静态值。另一方面,状态由组件维护和更新。让我们用一个例子来明白这个概念:
var App = React.createClass({
getInitialState: function(){
return {
message: 'this is a default message from state',
}
},
render: function(){
return (
<div>
<h1> {this.state.message} </h1>
</div>
);
}
});
React.render(<App />, document.getElementById('container'))
如果您运行这个代码片段,您将在欣赏器中看到如图 1-10 所示的结果。

图 1-10。
Resulting message using state
让我们看看代码。在同一个组件中,您使用关键字getInitialState初始化状态,在这个关键字中,您设置了消息的初始状态:
getInitialState: function(){
return {
message: 'this is a default message from state',
}
},
接下来,与上一个例子不同,您使用this.state.message来访问这个状态,它打印消息状态的初始文本:
<div>
<h1> {this.state.message} </h1>
</div>
现在让我们为您的组件添加一些功能。您在消息语句上方添加一个文本框。当您在文本框中键入内容时,消息会使用状态的概念实时更新:
var App = React.createClass({
getInitialState: function(){
return {
message: 'this is a default message from state',
}
},
updateState: function(e){
this.setState({message: e.target.value})
},
render: function(){
return (
<div>
<input type="text" onChange={this.updateState} />
<h1> {this.state.message} </h1>
</div>
);
}
});
React.render(<App />, document.getElementById('container'))
如果您在欣赏器中执行这段代码,您将会看到如图 1-11 所示的结果。

图 1-11。
Adding a text box above your message statement
让我们看看您向组件中添加了什么。起首,您引入了一个名为updateState的函数:
updateState: function(e){
this.setState({message: e.target.value})
}
这个新函数updateState接受一个名为(e)的变乱,并更新消息状态的值。此外,您还添加了一个输入字段:
<div>
<input type="text" onChange={this.updateState} />
<h1> {this.state.message} </h1>
</div>
输入框有一个onChange变乱,每当状态更新时,它调用您的定制方法updateState。当您在文本框中键入内容时,打印的信息会立即更新。
择要

本章提供了 React 的快速欣赏。在你开始下一章之前,让我们回顾一下到目前为止你所学的内容。向您先容了 React 库及其发明背后的原因。然后,您学习了怎样安装和设置 React。您学习了这项技能的基础,例如虚拟 DOM、单向数据流和 JSX。您还了解了组件,以及在组件中使用状态和属性。
现在,您已经准备幸亏 React 生态系统中编码和工作,您旅程的风趣路径将在下一章开始。您将开始使用 React Native。
二、最简单的程序:React Native 的 Hello World

“大事始于小事。”—普罗米修斯
在上一章中,您对 React 生态系统有了一个很好的概述。现在是时候用 React Native 弄脏你的手了。在本章中,您将通过安装先决条件来设置您的环境,然后您将创建您的第一个 React 本机应用。
最好的学习方法是通过实例。贯穿整本书的主题是,你将通过编程来跟随例子学习 React Native 以明白概念。
在本章中,您将探索以下主题:

Note
您大概会面临不同项目在不同节点版本上工作的情况。因此,建议您安装 NVM(节点版本管理器)来帮助保持可以在项目之间切换的多个节点版本。
什么是 React Native?

React Native 是一个开辟原生移动应用的开源平台;它主要是由脸书的一个团队开辟的。使用 React Native 很酷的一点是,您的程序使用标准的 web 技能,如 JavaScript (JSX)、CSS 和 HTML,而您的应用是完全原生的。换句话说,您的应用非常快速和流畅,它等同于任何使用传统 iOS 技能(如 Objective-C 和 Swift)构建的原生应用。然而,React Native 在性能和团体体验方面并没有妥协,就像盛行的使用 web 技能构建 iOS 应用的混合框架一样。
React Native 旨在将 React 的强大功能引入移动开辟,这一点在第一章的中有所表明。用 React 团队的话说,“学习一次,在任何地方写。”使用 React 和 React Native,您将看到许多使用 React 为 Web 构建的组件可以很容易地移植到 React Native iOS 应用,只需很少或不必要修改。React Native 引入了一种高度功能化的方法来构造用户界面,这与传统的 iOS 开辟方法有很大不同。
只管 React Native 是由脸书开辟者开辟的,但它是一个开源项目。该代码可在 https://github.com/facebook/reactreact-native 得到。
React 当地先决条件

在开始安装之前,让我们先回顾一下 React Native 的先决条件:

装置

让我们对 React Native 做一个快速的一次性设置。React Native 是 JavaScript 和 Objective-C 代码的混合体,因此您必要一些工具来创建、运行和调试用 JavaScript 编写的本机应用。我们一个一个来。
安装节点和 npm

Node.js 是创建在 Chrome 的 JavaScript 运行时之上的开源平台;它提供了一种轻松构建快速、可伸缩程序的方法。Node.js 允许您在终端中运行 JavaScript,并帮助创建模块。通过在终端中运行以下命令来安装 node . jsbrew install node。
自制是安装 Node 的保举方式。也可以从 https://nodejs.org 下载安装程序,手动安装。
npm 是 Node.js 的包管理器,如果你来自 iOS 天下,它类似于 CocoaPods。
通过在终端中运行以下命令来查抄节点安装:
>> node –v
v4.2.1
>> npm –v
2.13.1
安装 Watchman

当您的文件和记录发生变化时,Watchman 会观察它们。当匹配文件更改时,它还可以触发操纵(如重建资源)。更多详情,请访问 https://facebook.github.io/watchman/ 。
您可以通过运行以下命令来安装 Watchman:
$brew install watchman
安装 React 当地包

React Native 是一个 npm 包,所以使用下面的代码来安装React Native- cli模块:
npm install -g react-native-cli
更新 React 本机

React Native 和 iOS 都是快速移动的框架。建议每次有新版本时更新它们。升级 React Native 很简单。在终端中运行以下命令:
npm update -g react-native-cli
你的第一个应用

既然您已经对 React Native 有了充足的了解,并且已经设置好了系统,那么是时候创建您的第一个应用了。为了让事情变得简单,开始的时候跟着做就行了。偶然,单调地输入代码大概会让你感到与现实脱节,但现在跟着感觉走就充足了。记住模仿是一种强有力的学习情势;这是我们学习大部分技能的方式,比如说语言、阅读、写作,也是你学习 React Native 编程的方式。随着您的继承,这种方法将帮助您深入明白为什么您创作了某些代码。
在整本书中,你将创建一个应用,并把它从 Hello World 变成一个成熟的、发行级的应用,除了在某些地方我们必要脱离主题去独立探索一个概念。所以在你设置之前,先说一下你打算办理的题目。你将在本书过程中创建的应用计划办理一些住房题目;这将是任何盛行的房地产搜索应用的一个非常原始的版本。
我们称之为合租吧。它将有一些根本的功能,如列表,创建一个条目,地理定位一个属性,等等。随着操纵的举行,您将会看到各种 React 本机特性怎样适合您的应用。
那是相当多的,但是在这一章中,你将仅仅使用 React Native 和一些 Hello World 代码为你的项目创建根本的布局。
创建一个根本的骨架

启动终端并键入以下命令:
react-native init HouseShare
这段代码使用 CLI 工具构建一个 React 本机项目,该项目可以按原样构建和运行。该命令为 React 当地 iOS 项目创建根本的文件夹布局。接下来,让我们进入这个目录:
> cd HouseShare/ios/
现在,点击HouseShare.xcodeproj。这是一个 Xcode 项目文件,将在 Xcode 中打开您的项目。接下来,让我们在 iOS 模拟器中加载您的应用。要构建您的应用并将其加载到模拟器中,只需单击顶部的运行按钮(图 2-1 )或执行 Command + R。这将在 iOS 模拟器中编译、构建并启动您的项目(图 2-2 )。

图 2-2。
Using the iOS simulator

图 2-1。
Building by clicking the Run button
真的很快。由于一个简单的命令,您的项目标根本布局已经就绪,您的应用已经加载到模拟器中。另请注意,当您从 Xcode 运行应用时,“终端”会自动打开。这是 React Native 的节点包管理器。如果您取消此操纵,应用将制止工作。
终端打开,启动 React 原生打包器和一个服务器处置惩罚上述哀求(图 2-3 )。React 本机打包程序负责读取和构建 JSX(您将在背面看到)和 JavaScript 代码。

图 2-3。
The packager is ready
http://localhost:8081/index.ios.bundle
Note
如果终端没有启动,iPhone 表现红屏,运行npm start并保持终端打开。
在您喜好的任何编辑器中设置您的项目。React Native 并不强迫您,也没有偏好任何特定的编辑器,所以您可以继承默认使用 Xcode。但是,我们建议您在编辑器中打开您的项目,就像我们个人最喜好的 Sublime Text 一样。
在index.io.js做一些改动。事实上,删除文件中的全部代码。现在,添加以下代码:
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
} = React;
var HelloWorld = React.createClass({
render: function() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
HelloWorld !!
</Text>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
welcome: {
fontSize: 25,
textAlign: 'center'
}
});
AppRegistry.registerComponent('HouseShare', () => HelloWorld);
在 iOS 模拟器中按 Command + R,将刷新屏幕,如图 2-4 所示。(注意,在本书中,我们将使用 Command 键取代 CMD 键,这是等效的。)

图 2-4。
The screen is refreshed
真快!在几分之一秒的时间里,你可以看到你应用的变化。您不必要编译代码并重启模拟器来对本机更改做出 React。如果你从前做过任何原生 iOS 应用开辟,点击刷新来检察变化大概会像一个奇迹。
现在,让我们来明白代码。该文件的顶部是下面一行:
'use strict';
这启用了严格模式,这为 React 本机 JavaScript 代码添加了改进的错误处置惩罚。ECMAScript 规范的第五版引入了严格模式。严格模式更容易编写安全的 JavaScript,并将糟糕的语法转换成真正的错误。这对于调试任何示例和使用未声明的变量都非常重要。
接下来是下面一行:
var React = require('react-native');
这将加载 React 本机模块,并将其分配给可在您的代码中使用的 React 本机变量。React Native 使用与 Node.js 相同的模块加载技能,带有require函数;这大致相当于在 Swift 中链接和导入库。
之后,添加以下代码片段:
var {
AppRegistry,
StyleSheet,
Text,
View,
} = React;
您正在将多个对象属性分配给一个变量;这被称为赋值过程中的析构。这个很酷的特性是在 JavaScript ECMAScript 6 中提出的。固然它是可选的,但它非常有益;否则,每次在代码中使用组件时,都必须使用完全限定名,例如 React。模仿,React。样式表等等。这节省了不少时间。
接下来,您将创建一个视图:
var HelloWorld = React.createClass({
render: function() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
HelloWorld !!
</Text>
</View>
);
}
});
React Native 的根本构建块称为组件。您可以使用createClass方法来创建定制的组件类。这个类只有一个函数,render()。render功能负责屏幕上表现的内容。您使用 JavaScript 语法扩展(JSX)来出现 UI。JSX 是一种 JavaScript 语法扩展,看起来类似于 XML。
现在,您可以界说应用的样式。这里你会用到 Flexbox 它类似于 CSS 之于 HTML。现在,您可以键入以下代码。我们将在下一章表明样式。
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
welcome: {
fontSize: 25,
textAlign: 'center'
}
});
你可以看到这种风格与 CSS 非常相似;您可以界说字体大小、对齐方式等。
最后一步是界说应用的入口点和根组件:
AppRegistry.registerComponent('HouseShare', () => HelloWorld);
这不是 UIWebView

您正在使用 web 技能,但您的应用没有 web 组件;它有一个当地组件。打开调试➤视图调试➤捕获视图层级(见图 2-5 )。

图 2-5。
Using the native component
当您遍历 UIWindow 的树时,您会看到代码中没有 UIWebView,以及“Hello World!!"是 RCTText 的调用,如图 2-6 。

图 2-6。
“Hello World !!” is the call of RCTText
启用实时重新加载

React Native 的另一个很酷的功能是 live reload。一旦有变化,它会在 iOS 模拟器中重新加载您的应用视图。要激活此选项,您必要通过按 Ctrl + Command + Z 从 iOS 模拟器中打开的应用访问开辟者菜单,并选择启用实时重新加载选项。现在,对 JavaScript 代码所做的任何更改都会导致应用自动重新加载。
React Native 为什么不一样?

在深入 React 当地天下之前,您必须明白为什么必要另一个框架来构建移动应用。我们已经生活在一个充满能够构建移动应用的框架和工具链的天下里。在 React Native 出现之前,使用 web 技能构建移动应用可以通过两种计谋实现:

使用这些计谋创建的应用存在性能题目。基于 WebView 的应用很慢,因为它们使用 DOM,并且 DOM 操纵非常昂贵,这导致了性能题目。正如 Flipboard ( http://engineering.flipboard.com/2015/02/mobile-web/ ))的一篇博文中所说,“你不能用 DOM 构建 60fps 的滚动列表视图。”这是通过这种技能开辟的应用的一个根本题目:只管开辟时间大概很快,但您终极会体验迟缓。
另一种计谋是框架模仿 JavaScript 和 HTML,并将它们转换成当地代码,这种计谋有其他挑战。只管终极的应用本质上是原生的,但在从 JavaScript 到原生的转换过程中有一个根本题目:它运行在主线程上。在这些应用中,你总是直接与当地对象交互,这又一次导致了痴钝而呆滞的体验。
React Native 从根本上不同于这两种方法。它在单独的线程上运行全部布局,你的主线程自由更新 UI,使得动画和 UI 渲染流畅,就像 100%纯原生 app 一样。
React Native 使用 JavaScriptCore 框架运行 JavaScript。在 iOS 7 中,苹果为 JavaScriptCore 引入了原生的 Objective-C API。这个框架允许 JavaScript 和 Objective-C 相互交流。这意味着您可以从 Objective-C 创建并调用 JavaScript 函数,或者从 JavaScript 回调 Objective-C。这一切都像魔咒一样管用。
React Native 另有一个不同之处。正如您在 Hello World 示例中看到的,您用 JavaScript 编写一个组件,就像您用 React 一样,只是您没有使用 HTML div,而是使用了像 View 和 Text 如许的标签。在 iOS 应用的情况下,视图根本上是 UIView。
React 本机应用的剖析

现在让我们明白 React Native init命令天生的应用布局。如果您打开名为 HouseShare 的项目,它看起来就像一个平常的 Xcode 项目。它具有以下文件夹布局:
|ios
|- HouseShare
|- HouseShare.xcodeproj
|- HouseShareTests
|android
node_modules
index.ios.js
index.android.js
package.json
Note
随着框架的发展,这里界说的文件夹布局大概会改变或修改,但是大部分功能保持不变。
如果您在 Xcode 中打开项目,它将具有不同的文件夹布局。Xcode 中的“文件夹”实际上是群组,不肯定链接到 Finder 中的文件夹。

让我们从HouseShare/ios/HouseShare/AppDelegate.m打开AppDelegate.m文件:
#import "AppDelegate.h"
#import "RCTRootView.h"
@implementation AppDelegate
- (BOOL)applicationUIApplication *)application didFinishLaunchingWithOptionsNSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
/**
* Loading JavaScript code - uncomment the one you want.
*
* OPTION 1
* Load from development server. Start the server from the repository root:
*
* $ npm start
*
* To run on a device, change localhost to the IP address of your computer
* (you can get this by typing ifconfig into Terminal and selecting the
* inetvalue underen0 and make sure your computer and iOS device are
* on the same Wi-Fi network.
*/
jsCodeLocation = [NSURL URLWithString"``http://localhost:8081/index.ios.bundle
/**
* OPTION 2
* Load from pre-bundled file on disk. To re-generate the static bundle
* from the root of your project directory, run
*
* $ react-native bundle --minify
*
* seehttp://facebook.github.io/react-native/docs/runningondevice.html
*/
//   jsCodeLocation = [[NSBundle mainBundle] URLForResource"main" withExtension"jsbundle"];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName"HouseShare"
launchOptions:launchOptions];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [[UIViewController alloc] init];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
RCTRootView是 React Native 提供的 Objective-C 类,继承自 iOS UIView类。它获取并执行您的 JavaScript 代码。
它还加载了http://localhost:8081/index.ios.bundle URL,其中有您用index.ios.js编写的代码,另有一个由 React 本机框架添加的程序。
排除故障

用 React Native 调试符合我们调试 web 应用的方式;总之,真的很简单。要访问调试选项,请在 iOS 模拟器中加载的应用内按 Command + D。这将打开一个提供几个调试选项的菜单,如图 2-7 所示。

图 2-7。
Debugging options
您必须为终极版本禁用此菜单,因为您的终极用户不应看到这些选项。要禁用它,请在 Xcode 中打开项目,然后选择:产品➤方案➤编辑方案(或按 Command +)
让我们回顾一下图 2-7 中表现的每个选项。
重新加载

reload 选项使用最新的 React 本机代码刷新模拟器中的屏幕,而无需再次编译项目。这可以通过两种方式实现:一、点击菜单中的重新加载选项,如图 2-7 所示,或者按 Command + R,如许会重新加载 JavaScript 代码中所做的全部更改。
在 Swift 或 Objective-C 文件中所做的任何更改都不会反映出来,因为这些更改必要重新编译。此外,如果您添加任何资产,如图像,应用必要重新启动。
在 Chrome 中调试

这是调试用 React Native 编写的 JavaScript 代码的最好和最常用的选项之一。与 web 应用一样,你可以在 Chrome 中调试 React 原生应用。当你点击“在 Chrome 中调试”时,它会在 Chrome 中打开http://localhost:8081/debugger-ui(图 2-8 )。

图 2-8。
Debugging in Chrome
安装 React 开辟工具,这是一个 Chrome 扩展,用于调试 React 应用和 React 本机代码。它允许您在 Chrome 开辟者工具中查抄 React 当地组件条理布局。要安装它,请访问 Chrome 网上商店或访问以下网址: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en 。
一旦安装了扩展,按 Command + Option + J 或者从 Chrome 欣赏器中选择检察➤开辟者➤开辟者工具来访问开辟者工具控制台。
你将会在你的 Chrome 开辟工具中得到一个名为 React 的新标签。这向您表现了已经出现在页面上的根 React 组件,以及它们终极出现的子组件。还可以看到属性、状态、组件、变乱监听器,如图 2-9 所示。

图 2-9。
Debugging in Chrome DevTools
检察图 2-10 ,你可以看到一个类似于 Xcode 的条理布局:Hello World 被包装在 RCTText 中,然后又被包装在 RCTview 中。

图 2-10。
Debugging the app with the React tab in Chrome DevTools
在 Safari 中调试

如果你没有 Chrome,你也可以使用 Safari 举行调试,但 Chrome 是调试 React 原生应用的首选。
表现 FPS 监视器

许多应用使用大量的动画和图形。FPS(每秒帧数)为您的应用界说这些动画的平滑度;这在游戏应用中被广泛使用。当您在菜单中选择“表现 FPS 监视器”时,它会在模拟器中表现您的应用的一些属性(图 2-11 )。固然你大概在你的 Hello World 应用中找不到这些属性的太多用途,但它们对于动画密集型应用来说非常有用,可以防止它们进入昏睡模式,从而创建不稳定的用户体验。见图 2-11 。

图 2-11。
Additional properties in the simulator
该查抄元件

您还可以从模拟器中查抄 React 当地元素,有点类似于您在欣赏器中查抄元素的方式,只管您目前不能像在欣赏器中那样更改属性的实时值。现在,您可以看到任何对象的样式表属性。点击 HelloReact!!文本(图 2-12 ),它将打开该元素的详细信息。

图 2-12。
Click the text to see element details
该元素的详细信息表现在左下方的图 2-13 中。

图 2-13。
Font details
你可以看到 Hello World 的字体大小是 25,并且居中对齐。
开始分析

剖析用于衡量绩效。概要分析会话提供了对代码的哪些部分最常用、必要多少时间以及应该改进代码的哪些部分的深入了解。您还可以从分析器在一个方法上制止的次数中找到每个方法耗费的时间。
下面的 URL 链接到一篇非常好的博客文章,这篇文章将很好地概述怎样使用 Xcode 举行分析: www.raywenderlich.com/23037/how-to-use-instruments-in-xcode .
择要

在这一章中,你被先容到 React 原生。您设置了 React 本机开辟环境,并编写了第一个应用。您还了解了 React 本机应用的文件夹布局以及怎样调试。现在,您已经做好了准备,可以开始使用 React Native 为您的 iOS 应用创建用户界面了。
在下一章中,您将学习怎样通过把握 Flexbox 来创建令人赞叹的用户界面。您将看到怎样从一个组件导航到另一个组件,怎样将图像添加到未封装的应用中,以及怎样使用 React Native 创建 ListView 和 ScrollView。
三、画布、画笔和颜料:使用用户界面

用户界面是从混乱的复杂到优雅的简单的变化过程—阿克沙特·保罗
在前一章中,我们先容了 React Native 并创建了我们的第一个 React Native 应用。现在我们的项目有了一个空缺的框架,我们将用一个令人赞叹的用户界面来添补它。在本章中,我们将讨论以下主题:

任何有经验的软件专业人士都会同意——一个应用的成功取决于它不仅运行完善,而且看起来很棒。因此,一个良好的用户界面对你的应用的成功有着巨大的影响。
布局系统是一个必要把握的根本概念,以便创建良好的应用。让我们起首了解怎样使用 React Native 在 iOS 应用中导航。
导航仪

NavigatorIOS 是一个用于创建导航的 React 当地组件。它包装了 UIKit 导航,并允许你在应用中添加向后滑动功能。NavigatorIOS 管理一堆视图控制器,以便为分层内容提供一个向下钻取的界面。现在我们知道 NavigatorIOS 是做什么的了,让我们在项目中实现它。
起首,在index.ios.js文件的组件列表中添加 NavigatorIOS:
var {
AppRegistry,
StyleSheet,
Text,
View,
NavigatorIOS,
} = React;
现在让我们创建一个具有 NavigatorIOS 的组件,并将其命名为mainView,然后让我们在mainView中加载另一个组件,我们将其命名为Home:
var mainView = React.createClass ({
render: function() {
return (
<NavigatorIOS
style={styles.navigator} initialRoute={{
title: 'House Share',
component: Home
}}
/>
);
},
});
Home component will be like home page of our application.
NavigatorIOS 是一个 React 本机组件;我们还使用initialRoute为页面提供了标题(House Share)和组件名称(Home)。另有其他选项,记录在 https://facebook.github.io/react-native/docs/navigatorios.html 中。
NavigatorIOS 有助于最根本的 IOS 路由。蹊径是描述导航器中每个视图的对象。起首,将蹊径提供给导航员。在前面的代码中,我们从我们的mainView调用组件 Home。让我们添加一个空的 Home 组件:
var Home = React.createClass({
render: function() {
return (
<View>
</View>
);
}
});
让我们也给我们的mainView组件添加一些样式:
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
welcome: {
fontSize: 25,
textAlign: 'center'
},
navigator: {
flex: 1
}
});
现在让我们将应用的入口点更新为mainView:
AppRegistry.registerComponent('HouseShare', () => mainView);
现在让我们用 Xcode 构建我们的应用,看看结果,如图 3-1 所示。

图 3-1。
Our application, with updated navigation bar at the top
非常好——我们可以在顶部看到一个更新的导航栏。让我们给这个导航栏添加一些颜色,使我们的更改更加明显:
var mainView = React.createClass ({
render: function() {
return (
<NavigatorIOS barTintColor='#48BBEC' titleTextColor= "#FFFFFF" style={styles.navigator} initialRoute={{
title: 'House Share',
component: Home
}}
/>
);
},
});
我们已经使用barTintColor和titleTextColor给我们的导航栏添加了颜色(见图 3-2 )。

图 3-2。
Our toolbar now has color
我们在这一部分做了一些样式设计,如果你来自网格布局配景,这大概对你来说是新的东西。React Native 使用 Flexbox 举行样式化,我们将在下一节详细讨论。
flex box(flex box)的缩写情势

在前面的例子中创建我们的布局时,您肯定已经看到了样式中提到的flex属性。这是因为 React 原生应用使用 Flexbox 布局模子。
React 原生 Flexbox 布局模子的灵感来自于 CSS3 中的 CSS Flex Box 布局。React 原生团队专门为 iOS 重新编写了这一功能。Flexbox 背后的主要思想是能够创建布局,而不必担心不同的屏幕尺寸或设备方向。flex 容器扩展项目以添补可用空间,或者收缩项目以防止溢出。让我们了解一些 Flexbox 的根本知识,以加速我们的布局开辟。起首,让我们更新视图:
var Home = React.createClass({
render: function() {
return (
<View style={styles.container}>
<View style={styles.topBox} />
<View style={styles.bottomBox} />
</View>
);
}
});
我们已经创建了一个带有样式容器的主视图和两个带有样式topBox和bottomBox的子视图。现在,让我们创建样式:
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column'
},
welcome: {
fontSize: 25,
textAlign: 'center'
},
navigator: {
flex: 1
},
topBox: {
flex: 2,
backgroundColor: '#CCE5FF'
},
bottomBox: {
flex: 1,
backgroundColor: '#FFFFCC'
}
});
返回模拟器,使用 Command+R 刷新视图。

图 3-3。
Screen in portrait mode
现在,旋转模拟器,你会看到它自动调整这些彩色方框的大小。
让我们将模拟器改为风景模式(见图 3-4 )。这可以使用 Command +右/左箭头键(⌘+Left 箭头)轻松完成。您可以看到框是怎样调整其大小的,标题是怎样调整其宽度的,以便利用全部可用的空间。多亏了 Flexbox,一个相当费力的任务被简化了。

图 3-4。
Screen in landscape mode
现在,让我们回顾一下 flex 属性Flex-direction和Flex。
弯曲方向

Flexbox 是一个单向布局概念。Flex-direction允许你界说子元素的流向。它可以有两个值,row和column。在前面的例子中,我们使用了column。
我们改成row:
container: {
flex: 1,
flexDirection: 'row'
}
返回模拟器,用命令+R 刷新视图(见图 3-5 )。

图 3-5。
Changing the orientation of the box
我们可以看到盒子的方向是怎样变化的。现在再次将属性flexDirection改为列(见图 3-6 ))。

图 3-6。
Changing the property to column
弯曲

您肯定见过样式表中的flex值;它可以是整数或小数,表示盒子的相对大小:
container: {
flex: 1,
flexDirection: 'column'
},
topBox: {
flex: 2,
backgroundColor: '#CCE5FF',
},
bottomBox: {
flex: 1,
backgroundColor: '#FFFFCC'
}
我们的观点是:
<View style={styles.container}>
<View style={styles.topBox} />
<View style={styles.bottomBox} />
</View>
所以flex界说了盒子的大小百分比。我们可以看到容器内部有两个视图,topBox和bottomBox,分别有2和1的flex值(见图 3-7 )。

图 3-7。
Container in 2:1 ratio
现在,更新视图并在容器视图中添加一个topBox视图:
<View style={styles.container}>
<View style={styles.topBox} />
<View style={styles.bottomBox} />
<View style={styles.topBox} />
</View>
刷新视图。容器现在有三个视图:topBox、bottomBox,然后又是topBox(见图 3-8 )。

图 3-8。
Container with three views
这将把视图分成 2:1:2 的比例,因为它们的flex值是 2:1:2 的比例。
为了更好地明白这是怎样工作的,让我们改变flex值,看看它怎样改变我们的屏幕。让我们把topBox的flex值改成1。
让我们将 CSS 更新为:
container: {
flex: 1,
flexDirection: 'column'
},
topBox: {
flex: 1,
backgroundColor: '#CCE5FF',
},
bottomBox: {
flex: 1,
backgroundColor: '#FFFFCC'
}
刷新视图检察变化,如图 3-9 所示。

图 3-9。
View in ratio of 1:1:1
我们可以看到,现在屏幕被分割成 1:1:1 的比例,因为视图的flex值是 1:1:1 的比例。使用 Flexbox,很容易创建可以根据屏幕大小和方向调整大小的布局。这只是对 Flexbox 的先容;我们将在必要时在整本书中表明更多的属性。您还可以在 https://facebook.github.io/react-native/docs/flexbox.html 找到更多选项。
添加图像

React Native 有一个内置组件Image,它将帮助我们表现图像,包括网络图像、暂时当舆图像,以及来自当地磁盘的图像,如相机胶卷。起首,我们将表现当舆图像。
在 Xcode 中打开Image.xacassets文件(参见图 3-10 )。点击底部的+按钮。

图 3-10。
Image.xacassets in Xcode
将图像集命名为“主页”,并将主页图像拖动到屏幕上的方框中(参见图 3-11 )。

图 3-11。
Image set “home”
xcassets 的使用是 iOS 7 之后的新标准。资产目录管理应用的图像;iOS 有不同的图像分辨率,并将它们分组在一起。构建时,Xcode 会将这个图像目录编译成最有效的包,以便终极分发。
既然我们已经将图像添加到了项目中,那么让我们将它添加到组件中。起首,将Image组件添加到我们的组件列表:
var {
AppRegistry,
StyleSheet,
Text,
View,
NavigatorIOS,
Image
} = React;
现在让我们将图像添加到我们的视图中:
var home = React.createClass({
render: function() {
return (
<View style={styles.container}>
<View style={styles.topBox} >
</View>
<View style={styles.bottomBox} >
<Image source={require('image!home')} style={styles.image}/>
</View>
<View style={styles.topBox} >
</View>
</View>
);
}
});
require('image!home)指向名为home的图像的资产目录。
让我们也指定这个图像的宽度和高度:
image: {
width: 70,
height: 70
},
由于我们在 Xcode 中做了改动,所以我们必须重启模拟器。制止应用并重新天生代码。我们可以看到房子的图像表现在屏幕上(见图 3-12 )。

图 3-12。
Now we have a house image
现在,让我们通过用下面的样式更新bottomBox来添加一些样式:
bottomBox: {
flex: 1,
backgroundColor: '#FFFFCC',
alignItems: 'center',
justifyContent: 'center',
},
alignItems和justifyContent分别界说沿横轴和主轴分列伸缩项目标默认行为。因为我们想在中间表现这个,所以我们将这些值更新为center。
刷新屏幕,你会发现房屋图像在视图中居中(见图 3-13 )。

图 3-13。
The house is now centered
我们还可以给定任何服务器图像 URL 作为源,并且Image组件将负责从网络加载它。我们将在本章的后半部分做这件事。
可触摸高亮表现

触摸是与 iOS 应用交互的根本方式。TouchableHighlight是一个 React 当地组件,它帮助我们创建按钮,以便在触摸时做出精确的相应。这些实际上不是按钮,但是 React 原生团队以为直接在 JavaScript 中构造按钮比使用 UIButton 更容易。你 app 里的按钮用的是TouchableHighlight,不是按钮,但工作起来像按钮。让我们用一个例子来明白这一点。
让我们将 TouchableHighlight 组件添加到代码中:
var {
AppRegistry,
StyleSheet,
Text,
View,
NavigatorIOS,
TouchableHighlight
} = React;
更新视图并添加两个TouchableHighlight按钮:
var Home = React.createClass({
render: function() {
return (
<View style={styles.container}>
<View style={styles.topBox} />
<View style={styles.bottomBox} />
<View style={styles.topBox} >
<TouchableHighlight style={styles.button}
underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Show Houses</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button}
underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Add House</Text>
</TouchableHighlight>
</View>
</View>
);
}
});
当然,我们必要按钮的样式表:
button: {
flex: 1,
backgroundColor: '#48BBEC',
borderColor: '#48BBEC',
borderWidth: 1,
borderRadius: 8,
alignSelf: 'stretch',
justifyContent: 'center',
margin: 10
},
buttonText: {
fontSize: 18,
color: 'white',
alignSelf: 'center'
}
在 iOS 模拟器中刷新应用。我们将在第三个块的屏幕上看到两个按钮(如图 3-14 所示)。

图 3-14。
Screen with two buttons at bottom
让我们继承构建我们的页面,再添加一个视图来列出住房选项。这将通过单击 show house 页面来完成,该页面将重定向到另一个组件。将以下代码替换为Home组件:
var Home = React.createClass({
_handleListProperty: function() {
console.log(‘Button clicked successfully’);
},
render: function() {
return (
<View style={styles.container}>
<View style={styles.topBox} />
<View style={styles.bottomBox} />
<View style={styles.topBox} >
<TouchableHighlight
style={styles.button}
onPress= {this._handleListProperty }
underlayColor='#99d9f4'
>
<Text style={styles.buttonText}>List properties</Text>
</TouchableHighlight>
<TouchableHighlight style={styles.button}
underlayColor='#99d9f4'>
<Text style={styles.buttonText}>Add House</Text>
</TouchableHighlight>
</View>
</View>
);
}
});
让我们回顾一下我们在这里做了什么;我们已经为列表属性部分的TouchableHighlight组件添加了一个onPress属性。每当有人按下列表属性按钮时,就会调用函数_ handleListProperty。
如果您构建您的应用并在开辟工具中打开控制台,每次您单击列表属性按钮时,您都会在控制台中看到消息“按钮已成功单击”。
接下来,我们将创建我们的ListProperty组件。但是起首,让我们重构我们的代码,并将我们的组件保存在单独的文件中。创建一个包含Components子文件夹的App文件夹,这是我们保存 React 当地组件的地方。在Components文件夹中,创建文件Home.js,并将它各自的组件放在那里。然后我们将在我们的index.ios.js中要求它们,现在看起来像如许:
'use strict';
var React = require('react-native');
var Home = require('./App/Components/Home');
var {
AppRegistry,
StyleSheet,
Text,
View,
NavigatorIOS,
TouchableHighlight
} = React;
var mainView = React.createClass ({
render: function() {
return (
<NavigatorIOS barTintColor='#48BBEC' titleTextColor= "#FFFFFF" style={styles.navigator} initialRoute={{
title: 'House Share',
component: Home
}}/>
);
},
});
var styles = StyleSheet.create({
navigator: {
flex: 1
}
});
AppRegistry.registerComponent('HouseShare', () => mainView);
路由到组件

在 React Native 中,您将构建许多组件,并在它们之间往返路由。我们必须有办法做到这一点。在本节中,我们将学习从一个组件到另一个组件的路由。在创建组件ListProperty之前,我们必要导航到这个组件的路径。这可以通过修改Home组件中的_handleListProperty函数来实现。在./App/Components/Home.js用以下代码替换_handleListProperty功能:
_handleListProperty: function() {
this.props.navigator.push({
title: "List Properties",
component: ListProperty
})
},
在这里,navigator.push向前导航到新的蹊径;这种情况下是ListProperty。
现在让我们通过在./App/Components/文件夹中创建一个文件ListProperty.js来创建一个List Property组件。在您的ListProperty.js文件中添加以下代码:
var React = require('react-native');
var {
View
} = React;
var ListProperty = React.createClass({
render: function() {
return (
<View />
);
}
});
module.exports = ListProperty;
刷新您的应用并点击列表属性按钮,这将把您带到如图 3-15 所示的空视图。

图 3-15。
Empty view with traversing option
在左上角,您将看到一个选项,可以遍历回上一个组件。NavigatorIOS 维护这个返回栈,通过它可以返回到上一个组件。现在让我们来处置惩罚这个空组件。这个想法是创建一个包含属性列表的表格视图,每个属性的左侧都有一个图像缩略图。其余的细节应该出现在它的旁边。
为了简化本章,我们将模拟数据,而不是从外部服务中提取数据(稍后,您将学习怎样从外部 API 中提取相同的数据)。有了这些数据,我们将表现酒店的名称、地址和缩略图。这看起来有点像图 3-16 。

图 3-16。
Property name and address
将以下代码添加到文件./App/Components/ListProperty.js中的ListProperty组件中:
var React = require('react-native');
var {
Image,
StyleSheet,
Text,
View
} = React;
var MOCK_DATA = [
{name: 'Mr. Johns Conch house', address: '12th Street, Neverland', images: {thumbnail: 'http://hmp.me/ol5
];
var ListProperty = React.createClass({
render: function() {
var property = MOCK_DATA[0]
return (
<View style={styles.container}>
<Image
source={{uri: property.images.thumbnail}}
style={styles.thumbnail}/>
<View style={styles.rightContainer}>
<Text style={styles.name}>{property.name}</Text>
<Text style={styles.address}>{property.address}</Text>
</View>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 53,
height: 81,
},
rightContainer: {
flex: 1,
},
name: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
address: {
textAlign: 'center',
},
});
module.exports = ListProperty;
让我们在 iOS 模拟器中刷新我们的应用,看看有什么变化(见图 3-17 )。

图 3-17。
Thumbnail image with property name and address
让我们回顾一下我们在这里做了什么:
var React = require('react-native');
var {
Image,
StyleSheet,
Text,
View
} = React;
我们起首指定了本节中要使用的全部组件。我们再次添加了Image组件,它将用于加载我们的图像——不是从一个捆绑的图像,而是像前面答应的那样,从一个图像 URL。
接下来,我们添加了一些模拟数据:
var MOCK_DATA = [
{name: 'Mr. Johns Conch house', address: '12th Street, Neverland', images: {thumbnail: 'http://hmp.me/ol5
];
这里,我们为我们的属性缩略图添加了名称、地址和图像 URL。随着示例的深入,我们将向这个模拟数据添加更多的值。
接下来,我们创建了我们的ListProperty组件:
var ListProperty = React.createClass({
render: function() {
var property = MOCK_DATA[0]
return (
<View style={styles.container}>
<Image
source={{uri: property.images.thumbnail}}
style={styles.thumbnail}/>
<View style={styles.rightContainer}>
<Text style={styles.name}>{property.name}</Text>
<Text style={styles.address}>{property.address}</Text>
</View>
</View>
);
}
});
我们的ListProperty组件有一个变量属性,它包含来自MOCK_DATA数组的数据。然后我们使用一个View组件来创建一个包含图片组件中缩略图的视图。在Image组件中,我们有属性 source,它可以有值 http address、当地文件路径或静态图像资源的名称。
使用一个Text组件,我们从模拟数据中指定了名称和地址:
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 53,
height: 81,
},
rightContainer: {
flex: 1,
},
name: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
address: {
textAlign: 'center',
},
});
module.exports = ListProperty;
最后,我们添加了样式并导出了我们的ListProperty组件。
列表视图

在上一节中,我们通过指定元素的索引来填凑数组中的一个元素。在本节中,我们将使用ListView添补一个数据列表。在我们开始之前,让我们多了解一点关于ListView组件的知识。
一个ListView是为添补动态数据的垂直滚动列表而设计的组件。最简单的步调是创建一个ListView数据源,用类似于当地TableView数据源的数据数组添补它,然后用该数据源和一个renderRow回调实例化一个ListView组件。这从数据数组中取出一个 blob,并返回一个可出现的组件,它将被表现。
ListView看起来与TableView非常相似,但是实现并没有真正使用TableView.,而是在幕后使用了ScrollView。像滑动删除、重新排序等功能不能通过ListView直接使用。
替换您的ListProperty.js中的以下代码:
var React = require('react-native');
var {
Image,
StyleSheet,
Text,
View,
ListView
} = React;
var MOCK_DATA = [
{name: 'Mr. Johns Conch house', address: '12th Street, Neverland', images: {thumbnail: 'http://hmp.me/ol5
{name: 'Mr. Pauls Mansion', address: '625, Sec-5,  Ingsoc', images: {thumbnail: 'http://hmp.me/ol6
{name: 'Mr. Nalwayas Villa', address: '11, Heights, Oceania', images: {thumbnail: 'http://hmp.me/ol7
{name: 'Mr. Johns Conch house', address: '12th Street, Neverland', images: {thumbnail: 'http://hmp.me/ol5
{name: 'Mr. Pauls Mansion', address: '625, Sec-5,  Ingsoc', images: {thumbnail: 'http://hmp.me/ol6
{name: 'Mr. Nalwayas Villa', address: '11, Heights, Oceania', images: {thumbnail: 'http://hmp.me/ol7
{name: 'Mr. Johns Conch house', address: '12th Street, Neverland', images: {thumbnail: 'http://hmp.me/ol5
{name: 'Mr. Pauls Mansion', address: '625, Sec-5,  Ingsoc', images: {thumbnail: 'http://hmp.me/ol6
{name: 'Mr. Nalwayas Villa', address: '11, Heights, Oceania', images: {thumbnail: 'http://hmp.me/ol7
];
var ListProperty = React.createClass({
getInitialState: function() {
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
return {
dataSource: ds.cloneWithRows(MOCK_DATA),
};
},
render: function() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderProperty}
style={styles.listView}/>
);
},
renderProperty: function(property) {
return (
<View style={styles.container}>
<Image
source={{uri: property.images.thumbnail}}
style={styles.thumbnail}/>
<View style={styles.rightContainer}>
<Text style={styles.name}>{property.name}</Text>
<Text style={styles.address}>{property.address}</Text>
</View>
</View>
);
},
});
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
thumbnail: {
width: 63,
height: 91,
},
rightContainer: {
flex: 1,
},
name: {
fontSize: 20,
marginBottom: 8,
textAlign: 'center',
},
address: {
textAlign: 'center',
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
});
module.exports = ListProperty;
在 iOS 模拟器中刷新您的应用以检察更新后的视图,如图 3-18 所示。

图 3-18。
Scrollable addresses
太好了。现在我们有了一个可以滚动欣赏的属性列表。现在让我们回顾一下实施情况:
var React = require('react-native');
var {
Image,
StyleSheet,
Text,
View,
ListView
} = React;
我们再次指定了本节中全部组件的用途。增长了一个新组件— ListView。如果你看过除了ListView之外的 React 原生文档来实现类似的功能,那么ScrollView. ListView大概比简单地出现全部这些元素或者将它们放在ScrollView中要好得多。这是因为,只管 React Native 速率很快,但出现一个非常大的元素列表大概会很慢。与TableView类似,ListView实现元素的渲染列表,如许你只表现屏幕上表现的元素;那些已经渲染但现在不在屏幕上的将从本机视图条理布局中删除,这使得渲染平滑而快速。
展望未来,我们已经更新了我们的MOCK_DATA:
var MOCK_DATA =[
{name: 'Mr. Johns Conch house', address: '12th Street, Neverland', images: {thumbnail: 'http://hmp.me/ol5
{name: 'Mr. Pauls Mansion', address: '625, Sec-5,  Ingsoc', images: {thumbnail: 'http://hmp.me/ol6
{name: 'Mr. Nalwayas Villa', address: '11, Heights, Oceania', images: {thumbnail: 'http://hmp.me/ol7
{name: 'Mr. Johns Conch house', address: '12th Street, Neverland', images: {thumbnail: 'http://hmp.me/ol5
{name: 'Mr. Pauls Mansion', address: '625, Sec-5,  Ingsoc', images: {thumbnail: 'http://hmp.me/ol6
{name: 'Mr. Nalwayas Villa', address: '11, Heights, Oceania', images: {thumbnail: 'http://hmp.me/ol7
{name: 'Mr. Johns Conch house', address: '12th Street, Neverland', images: {thumbnail: 'http://hmp.me/ol5
{name: 'Mr. Pauls Mansion', address: '625, Sec-5,  Ingsoc', images: {thumbnail: 'http://hmp.me/ol6
{name: 'Mr. Nalwayas Villa', address: '11, Heights, Oceania', images: {thumbnail: 'http://hmp.me/ol7
];
在这段代码中,我们添加了更多的条目来创建一个可滚动的视图。现在,让我们看看我们在ListProperty组件中所做的更改:
var ListProperty = React.createClass({
getInitialState: function() {
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
return {
dataSource: ds.cloneWithRows(MOCK_DATA),
};
},
render: function() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderProperty}
style={styles.listView}/>
);
},
renderProperty: function(property) {
return (
<View style={styles.container}>
<Image
source={{uri: property.images.thumbnail}}
style={styles.thumbnail}/>
<View style={styles.rightContainer}>
<Text style={styles.name}>{property.name}</Text>
<Text style={styles.address}>{property.address}</Text>
</View>
</View>
);
},
});
这里我们设置getInitialState的组件规格:
getInitialState: function() {
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
return {
dataSource: ds.cloneWithRows(MOCK_DATA),
};
},
在安装组件之前,getInitialState仅被调用一次。返回值将作为this.state的初始值。
接下来,我们修改了render函数,如许,一旦我们有了数据,它就会出现一个ListView而不是一个条目:
render: function() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderProperty}
style={styles.listView}/>
);
},
renderProperty: function(property) {
return (
<View style={styles.container}>
<Image
source={{uri: property.images.thumbnail}}
style={styles.thumbnail}/>
<View style={styles.rightContainer}>
<Text style={styles.name}>{property.name}</Text>
<Text style={styles.address}>{property.address}</Text>
</View>
</View>
);
},
});
你会注意到我们使用了this.state中的dataSource,它已经由getIntialState设置好了。我们还调用了renderProperty函数来设置每一行的图像、名称和地址。最后,我们添加了一些样式:
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
卷动检视

固然我们没有在家里使用ScrollView,但是application, to populate a list we can use ScrollView just like we used ListView. ScrollView是 iOS 中最通用和最有用的控件之一,因为它是一种列出比屏幕尺寸大的内容的好方法。
我们可以通过使用下面的代码添加一个根本的ScrollView:
var scrollview = React.createClass({
getInitialState: function() {
return {
values: values
};
},
_renderRow: function(value, index) {
return (
<View
style={styles.row}
key={index}
>
<Text>{value + "  <----- Slide the row "}</Text>
</View>
)
},
render: function() {
return (
<View style={styles.container}>
<ScrollView style={styles.outerScroll}>
{this.state.values.map(this._renderRow, this)}
</ScrollView>
</View>
);
}
});
我们将为ScrollView设置getInitialState,如下所示:
var values = [1,2,3,4]
我们可以将这些值映射到_renderRow函数,该函数将返回一个根本视图,并带有一些文本。这是根本的ScrollView;如果我们想要程度滚动,并且我们想要锁定谁人方向,我们可以如许做:
<ScrollView
horizontal={true}
directionalLockEnabled={true}
>
使用ScrollView另有许多其他选项可用;有关文档和示例,您可以访问以下网址: https://facebook.github.io/react-native/docs/scrollview.html 。
择要

在这一章中,我们学习了一些创造令人赞叹的用户体验的基础知识。我们讨论了以下内容:

在下一章,我们将学习怎样通过使用 Flux 以不同的方式办理题目。我们不仅会发现怎样使用 flux 模式,还会发现它与无处不在的 MVC 模式有什么不同。我们还将使用 React 创建一个简单的 flux 应用,并将其移植到 React Native 中。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4