发布于 2026-01-06 3 阅读
0

使用 React Native 构建咖啡地图 进入 Expo Espressopedia 获取用户位置 获取数据

使用 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
Enter fullscreen mode Exit fullscreen mode

然后运行

exp init espressopedia
Enter fullscreen mode Exit fullscreen mode

它会询问你是要创建一个空白模板项目,还是创建一个包含一些初始文件(例如标签导航器)的项目。我选择了空白项目,因为我们不需要任何标签导航功能。

现在我将在 iOS 模拟器中测试该应用。您也可以使用自己的设备,但需要自行下载并安装 Expo 客户端。运行模拟器的步骤如下:

exp ios

# or for Android

exp android
Enter fullscreen mode Exit fullscreen mode

并建设该项目

exp start
Enter fullscreen mode Exit fullscreen mode

现在打开根目录,你会看到空白的模板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',
  },
});

Enter fullscreen mode Exit fullscreen mode

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%'
  }
}
Enter fullscreen mode Exit fullscreen mode

这个 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>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

这里我们传递一个初始区域对象,它会将地图放置在库比蒂诺市附近。我们会在获取用户位置信息后替换它,以便将地图视图居中。我们还将其用于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() { /* ... */ }
}

Enter fullscreen mode Exit fullscreen mode

在这里,我们会确保在应用启动时获得用户使用地理位置的权限。如果用户拒绝,我们会设置一个错误信息,并可以选择显示该错误信息而不是地图。获得权限后,我们可以调用getCurrentPositionAsync一个返回位置对象的函数,该对象比我们需要的要复杂一些,所以我们对其进行处理,只提取我们需要的属性,即纬度和经度(以及用于地图缩放的增量)。

正在获取数据

为了获取咖啡店数据,我们将查询 Yelp API。在 Yelp 上设置应用非常简单,只需登录并转到“管理应用”即可。在这里,您将获得一个 API 密钥,可用于调用他们的 API。

就像在网页上一样,我们可以利用 axios 库来执行 HTTP 请求。请运行

npm install --save axios
Enter fullscreen mode Exit fullscreen mode

为了实现模块化,我将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
};
Enter fullscreen mode Exit fullscreen mode

这项服务的工作原理是创建一个 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>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

现在一切就绪!你应该能看到一张带有标记的地图,以及你的位置。除非你正在使用模拟器。那样的话,你会看到你身处旧金山的某个地方。我很好奇世博会团队是不是在那里办公?

最终的

希望这篇文章能给你带来一些乐趣,也希望它能启发你做出更酷的东西。在准备这篇文章的过程中,我开发了一个类似的应用程序,功能更丰富一些,甚至还加入了筛选按钮。其中一个筛选器是“星巴克”,以防你找不到其他筛选器。如果你感兴趣,可以点击这里查看代码。

这是我的第一篇帖子,欢迎大家评论、建议或批评指正。这能提高互动率,也能确保以后的帖子写得更好。

下次再见。

文章来源:https://dev.to/iwilsonq/building-a-coffee-map-with-react-native--3b45