原文:http://www.raywenderlich.com/99473/introducing-react-native-building-apps-javascript
注意:全部图片放在了百度相冊空间。假设你看不到图片。请复制图片URL,然后粘贴到地址栏中进行查看。
開始搜索
为了实现搜索概念,我们须要处理Gobutton点击事件,创建相应的API请求,显示网络请求的状态。
打开SearchPage.js, 在constructor方法中改动state的初始化代码:
this.state = { searchString: 'london', isLoading: false }; |
isLoading 属性用于表示查询是否正在进行。
在render方法最上面添加:
var spinner = this.state.isLoading ? ( <ActivityIndicatorIOS hidden='true' size='large'/> ) : ( <View/>); |
用了一个三目运算。这是一个if语句的简单形式。假设isLoading为true,显示一个网络指示器,否则显示一个空的view。
在return语句中,在Image下添加:
{spinner} |
在Gobutton相应的 TouchableHighlight 标签中添加例如以下属性:
onPress={this.onSearchPressed.bind(this)} |
在 SearchPage 类中新增例如以下方法:
_executeQuery(query) { console.log(query); this.setState({ isLoading: true }); }
onSearchPressed() { var query = urlForQueryAndPage('place_name', this.state.searchString, 1); this._executeQuery(query); } |
_executeQuery() 眼下不过在控制台中输出一些信息,同一时候设置isLoading属性为true,剩下的功能我们留到后面完毕。
注意: JavaScript类没有訪问器。因此也就没有私有的概念。因此我们会在方法名前加一个下划线。以表示该方法视同为私有方法。
当Gobutton被点击。 onSearchPressed() 即被调用。
在 SearchPage 类声明之前,声明例如以下实用函数:
function urlForQueryAndPage(key, value, pageNumber) { var data = { country: 'uk', pretty: '1', encoding: 'json', listing_type: 'buy', action: 'search_listings', page: pageNumber }; data[key] = value;
var querystring = Object.keys(data) .map(key => key + '=' + encodeURIComponent(data[key])) .join('&');
return 'http://api.nestoria.co.uk/api? ' + querystring; }; |
这个函数不依赖SearchPage类,因此被定义为函数而不是方法。它首先将key\value參数以键值对形式放到了data集合中,然后将data集合转换成以&符分隔的“键=值”形式。=>语法是箭头函数的写法,一种创建匿名函数简洁写法。详细请參考
recentaddition to the JavaScript language 。
回到模拟器,按下 Cmd+R 重新启动App,然后点击‘Go’ button。你将看到网络指示器開始转动。
同一时候控制台将输出:
![](http://b.picphotos.baidu.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=53d41236b67eca80160539e2a118e6e0/9213b07eca806538ed12100691dda144ad34822f.jpg?</p><p>referer=462a4f3e9b16fdfa817bf2deeee5&x=.jpg)
网络指示器显示,同一时候要请求的URL也打印出来了。
拷贝并粘贴URL到Safari。查看搜索结果。
你将看到一堆JSON对象。我们将用代码解析这些JSON对象。
注意: 这个App使用 Nestoria API 来查找房子。
查找结果以JSON格式返回。
官方文档中列出了全部请求的URL规范及响应格式。
发送请求
打开 SearchPage.js。在初始化状态过程中添加一个message属性:
this.state = { searchString: 'london', isLoading: false, message: '' }; |
在render方法中。在UI元素的最后添加:
<Text style={styles.description}>{this.state.message}</Text> |
这个Text用于向用户显示一些文本。
在 SearchPage 类中,在 _executeQuery()方法最后添加:
fetch(query) .then(response => response.json()) .then(json => this._handleResponse(json.response)) .catch(error => this.setState({ isLoading: false, message: 'Something bad happened ' + error })); |
fetch 函数在 Fetch API中定义。这个新的JavaScript规范被Firefox 39(Nightly版)以及Chrome 42(开发版)支持,它在XMLHttpRequest的基础上进行了极大的改进。结果是异步返回的。同一时候使用了 promise规范。假设response中包括有效的JSON对象则将JSON对象的response成员(还有一个JSON)传到_handleResponse方法(后面实现)。
然后在 SearchPage类中添加方法:
_handleResponse(response) { this.setState({ isLoading: false , message: '' }); if (response.application_response_code.substr(0, 1) === '1') { console.log('Properties found: ' + response.listings.length); } else { this.setState({ message: 'Location not recognized; please try again.'}); } } |
假设查询结果成功返回,我们重置 isLoading 属性为false,然后打印结果集的总数。
注意: Nestoria有 不以1开头的响应码, 这些代码都很实用。
比如202 和 200表示返回一个推荐位置的列表。当完毕这个实例后。你能够尝试处理这些返回码。并将列表提供给用户选择。
保存,返回模拟器,按下Cmd+R ,然后搜索 ‘london’你将在控制台看到一条消息。表示搜索到20条房子信息。
尝试输入一个不存在的地名,比方 ‘narnia’ 你将看到例如以下信息:
![](http://c.picphotos.baidu.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=f1bb2b523f12b31bc36ccd2cb6234747/a8773912b31bb0517a2f043d307adab44aede098.jpg?referer=13b922c90efa513d08bd59ee4076&x=.jpg)
展现搜索结果
新建一个文件: SearchResults.js, 编写例如以下代码:
'use strict';
var React = require('react-native'); var { StyleSheet, Image, View, TouchableHighlight, ListView, Text, Component } = React; |
一条requires语句和一个结构赋值。
定义一个Componet子类:
class SearchResults extends Component {
constructor(props) { super(props); var dataSource = new ListView.DataSource( {rowHasChanged: (r1, r2) => r1.guid !== r2.guid}); this.state = { dataSource: dataSource.cloneWithRows(this.props.listings) }; }
renderRow(rowData, sectionID, rowID) { return ( <TouchableHighlight underlayColor='#dddddd'> <View> <Text>{rowData.title}</Text> </View> </TouchableHighlight> ); }
render() { return ( <ListView dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)}/> ); }
} |
上述代码中使用了一个专门的组件——ListView ——该组件很像ITableView。通过ListView.DataSource, 我们能够向ListView提供数据。renderRow函数则用于为每一个行提供UI。
在构建数据源的时候,我们使用箭头函数对不同的行进行识别。这个函数在ListView进行“一致化”的时候被调用。以便推断列表中的数据是否被改变。在本例中,NestoriaAPI有一个guid属性。刚好能够用来作为推断的标准。
最后,添加一条模块输出语句:
module.exports = SearchResults; |
SearchPage.js 头部。require 下方添加:
var SearchResults = require('./SearchResults'); |
这样我们就能够 SearchPage 类中使用SearchResults类了。
在_handleResponse 方法,将console.log 一句替换为:
this.props.navigator.push({ title: 'Results', component: SearchResults, passProps: {listings: response.listings} }); |
上述代码将导航至SearchResults 页面,并将请求到的列表数据传递给它。Push方法能够将页面添加到导航控制器的ViewController堆栈中,同一时候你的导航栏上将出现一个Backbutton。点击它能够返回到上一页面。
回到模拟器, 按下Cmd+R ,进行一个查找动作。
你将看到搜索结果例如以下:
![](http://h.picphotos.baidu.com/album/s%3D550%3Bq%3D90%3Bc%3Dxiangce%2C100%2C100/sign=eec13884cb11728b342d8c27f8c7b2f3/bba1cd11728b471086d34ad9c5cec3fdfc032322.jpg?referer=ee822f6ed71373f0ac285baf8de0&x=.jpg)