使用 React Native 构建咖啡地图
进入博览会
咖啡百科
获取用户位置
正在获取数据
这位年轻的网页开发者精通网页开发。他们花费了无数时间摆弄div元素和调整边距。他们用JavaScript、Python、Golang、Fortran、Basic……等等各种语言编写过无数待办事项应用程序!
但现在,这位才华横溢的开发者想要征服一个不太熟悉的领域。他想用当时最热门的新框架 React Native 取代团队里所有的移动开发人员。他以为这就像编写一个简单的 Web 应用程序一样简单,于是安装了 React Native CLI 并搭建了一个空项目。
一开始一切顺利。他们发现,不能使用 div 元素,而应该创建 View 元素。要创建文本,必须使用内置的 Text 组件。不能使用 CSS,而应该使用内联 JavaScript 样式。为了创建美观的布局,他们需要了解一些 Flexbox 的知识。
但他们随后又想使用更强大的功能,例如地理定位、音频输入或推送通知。他们发现,要启用这些功能,必须打开 Xcode,编辑一些相当冗长的配置文件,修改 plist 文件,并用 Objective-C 创建头文件和实现。他们觉得或许还是应该坚持使用 Web 技术。
进入博览会
幸运的是, Expo团队打造了一个功能强大的 SDK,极大地提升了 React Native 开发者的体验。他们让使用 Expo 创建应用时,你几乎无需打开 Xcode 或编辑任何平台特定的配置文件。
如果您熟悉使用 create-react-app 来创建 React Web 应用,那么 Expo 的工作方式与之非常相似。您exp init <project-name>只需在命令行运行 `expole.log`,然后进入项目目录并运行即可exp start。Expo 会生成一个二维码,您可以使用该二维码在设备上直接查看项目。您也可以使用 `expole.log`exp ios或 `expole.log`运行模拟器exp android。模拟器在保存之间速度稍快一些,但性能不如真机。
咖啡百科
它就像咖啡界的 Expedia,或者类似的东西。从宏观角度来看,这款应用的功能大致如下:
- 我们将提供一个地图视图,用户位置将显示在地图中心。
- 地图上会标出附近咖啡店和茶馆的位置。
我们将使用 Yelp API 获取咖啡店列表。他们的 API 设置和使用都非常简单,只需前往Yelp注册并创建一个应用即可。
创建新项目
让我们开始编写代码吧。首先安装 Expo CLI。
npm install -g exp
然后运行
exp init espressopedia
它会询问你是要创建一个空白模板项目,还是创建一个包含一些初始文件(例如标签导航器)的项目。我选择了空白项目,因为我们不需要任何标签导航功能。
现在我将在 iOS 模拟器中测试该应用。您也可以使用自己的设备,但需要自行下载并安装 Expo 客户端。运行模拟器的步骤如下:
exp ios
# or for Android
exp android
并建设该项目
exp start
现在打开根目录,你会看到空白的模板App.js文件。
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
View如果你是 React 老手,这个文件看起来应该不会太难。注意 `<style>`和 ` <style>` 标签的用法Text。这个文件使用了 `<style>` 标签StyleSheet,但我们也可以将样式定义为一个普通的对象。
绘制地图
我们将要探索的第一个 Expo API 是MapView组件。
// app/components/Map.js
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { MapView } from 'expo';
const Marker = MapView.Marker;
export default class Map extends Component {
renderMarkers() {
return this.props.places.map((place, i) => (
<Marker
key={i}
title={place.name}
coordinate={place.coords}
/>
));
}
render() {
const { region } = this.props
return (
<MapView
style={styles.container}
region={region}
showsUserLocation
showsMyLocationButton
>
{this.renderMarkers()}
</MapView>
);
}
}
const styles = {
container: {
width: '100%',
height: '80%'
}
}
这个 Map 组件是对 Expo 内置组件的封装MapView。通过封装内置组件,我们可以使用生命周期方法和应用程序特定的方法(例如渲染标记)来为地图添加功能。这里,它并非专门针对我们查找咖啡店的用例而实现——这个决定是在App.js渲染它的组件中做出的。
// App.js
import React from 'react';
import { Text, SafeAreaView } from 'react-native';
import Map from './app/components/Map'
// A placeholder until we get our own location
const region = {
latitude: 37.321996988,
longitude: -122.0325472123455,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421
}
export default class App extends React.Component {
state = {
region: null
coffeeShops: []
}
render() {
return (
<SafeAreaView style={styles.container}>
<Map
region={region}
places={this.state.coffeeShops}
/>
</SafeAreaView>
);
}
}
这里我们传递一个初始区域对象,它会将地图放置在库比蒂诺市附近。我们会在获取用户位置信息后替换它,以便将地图视图居中。我们还将其用于SafeAreaView顶层组件。这样即使在 iPhone X 特殊的屏幕区域设置下,我们的内容也能呈现良好的效果。
获取用户位置
要获取用户位置,我们可以使用 Expo 中的 `get_user_location`Location和 `get_user_location`Permissions模块。将此添加到App.js
// App.js
/* ... */
import { Location, Permissions } from 'expo'
const deltas = {
latitudeDelta: 0.0922,
longitudeDelta: 0.0421
};
export default App extends Component {
state = {
region: null,
coffeeShops: []
};
componentWillMount() {
this.getLocationAsync();
}
getLocationAsync = async () => {
let { status } = await Permissions.askAsync(Permissions.LOCATION);
if (status !== 'granted') {
this.setState({
errorMessage: 'Permission to access location was denied'
});
}
let location = await Location.getCurrentPositionAsync({});
const region = {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
...deltas
};
await this.setState({ region });
}
render() { /* ... */ }
}
在这里,我们会确保在应用启动时获得用户使用地理位置的权限。如果用户拒绝,我们会设置一个错误信息,并可以选择显示该错误信息而不是地图。获得权限后,我们可以调用getCurrentPositionAsync一个返回位置对象的函数,该对象比我们需要的要复杂一些,所以我们对其进行处理,只提取我们需要的属性,即纬度和经度(以及用于地图缩放的增量)。
正在获取数据
为了获取咖啡店数据,我们将查询 Yelp API。在 Yelp 上设置应用非常简单,只需登录并转到“管理应用”即可。在这里,您将获得一个 API 密钥,可用于调用他们的 API。
就像在网页上一样,我们可以利用 axios 库来执行 HTTP 请求。请运行
npm install --save axios
为了实现模块化,我将services在应用程序目录下添加一个名为 `<app_directory_name>` 的新文件夹,并在该文件夹下创建一个名为 `<app_directory_name>` 的文件yelp.js。在这里,我们定义了我们的应用程序如何与 Yelp 的 API 进行交互。
// app/services/yelp.js
import axios from 'axios';
const YELP_API_KEY = '<YOUR_API_KEY>';
const api = axios.create({
baseURL: 'https://api.yelp.com/v3',
headers: {
Authorization: `Bearer ${YELP_API_KEY}`
}
});
const getCoffeeShops = userLocation => {
return api
.get('/businesses/search', {
params: {
limit: 10,
categories: 'coffee,coffeeroasteries,coffeeshops',
...userLocation
}
})
.then(res =>
res.data.businesses.map(business => {
return {
name: business.name,
coords: business.coordinates
};
})
)
.catch(error => console.error(error));
};
export default {
getCoffeeShops
};
这项服务的工作原理是创建一个 HTTP 客户端,axios.create并传入baseURL请求头Authorization。然后,我们可以使用它向 Yelp API 发送带有https://api.yelp.com/v3/businesses/search查询参数的 GET 请求。Axios 简化了这一过程,允许我们将参数设置为参数列表中的对象。之后,此getCoffeeShops方法唯一使其适用于我们应用程序的部分是categories请求中指定的参数。我们可以将其更改为“vegan”或“burgers”,这将完全改变地图的结果。至少大部分会改变。
现在让我们在内部使用此服务App.js,首先导入 YelpService。
// App.js
/* ... */
import YelpService from './app/services/yelp'
export default App extends Component {
/* ... */
getCoffeeShops = async () => {
const { latitude, longitude } = this.state.region;
const userLocation = { latitude, longitude };
const coffeeShops = await YelpService.getCoffeeShops(userLocation);
this.setState({ coffeeShops });
};
getLocationAsync = async () => {
/* ... */
// Add this line!
await this.getCoffeeShops();
}
render() {
const { region, coffeeShops } = this.state;
return (
<SafeAreaView style={styles.container}>
<Map region={region} places={coffeeShops} />
</SafeAreaView>
);
}
}
现在一切就绪!你应该能看到一张带有标记的地图,以及你的位置。除非你正在使用模拟器。那样的话,你会看到你身处旧金山的某个地方。我很好奇世博会团队是不是在那里办公?
希望这篇文章能给你带来一些乐趣,也希望它能启发你做出更酷的东西。在准备这篇文章的过程中,我开发了一个类似的应用程序,功能更丰富一些,甚至还加入了筛选按钮。其中一个筛选器是“星巴克”,以防你找不到其他筛选器。如果你感兴趣,可以点击这里查看代码。
这是我的第一篇帖子,欢迎大家评论、建议或批评指正。这能提高互动率,也能确保以后的帖子写得更好。
下次再见。
文章来源:https://dev.to/iwilsonq/building-a-coffee-map-with-react-native--3b45
