DEV Community

loading...
Cover image for How I Made a Restaurant Finder App with React Native Part 1

How I Made a Restaurant Finder App with React Native Part 1

kpete2017 profile image Kyle Petersen Updated on ・6 min read

Introduction

React Native has been a game-changer in mobile development ever since it was first released back in March of 2015. Due to its flexibility, extensive libraries, and simplicity to learn for those already familiar with React. It has since then, been adopted by some of the largest companies on earth to build their mobile applications. Today, I would like to show you how I created a restaurant finder app using the Google Places API for a complete React Native beginner.

Installation

For this project, we are going to need a few things downloaded. We are also going to be using Expo CLI for our app.

  • First Download Node Package Manager to your appropriate operating system.
  • Then, within your terminal install Expo with npm install -g expo-cli.
  • Also, download the app Expo on your mobile device if you would like to test the app on your own physical hardware.

Initialization

To initialize a new react native project with Expo, run the command
expo init <name of project> --npm. In this case, we are going to name the project restaurant_finder. Once prompted to select a template, choose the 'blank' one for now. Once you open the project within a text editor of your choice, you should have a file structure similar to this.

Alt Text

Note: the --npm flag at the end of our command tells Expo to install all the dependencies with node package manager. Expo defaults to using yarn otherwise. Make sure you do not mix using these two package managers or it will cause errors.

We are going to now change our current directory into our project with cd restaurant_finder and install a couple of extra packages by running expo install expo-location and expo install expo-permissions. Once both of those packages are installed, we are going to start our project with npm start.

A new window should open up with the metro bundler front and center.

Alt Text

You can scan the barcode in the bottom left corner with your device to open the app we are working on. At the moment you should just see a blank screen with text that says "Open up App.js to start working on your app!".
We are going to do exactly that!

Go ahead and open app.js within your text editor and you should see a bunch of code that looks like this

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.js to start working on your app!</Text>
      <StatusBar style="auto" />
    </View>
  );
}
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
Enter fullscreen mode Exit fullscreen mode

Changing Our Component into a Class

Since we are going to be doing quite a bit of state manipulation we are going to go ahead and translate our functional component into a class-based component.

To do this we are going to replace the word 'function' with 'class' within our declaration and replacing the parenthesis with 'extends React.Component'.

After this, we need to remove the 'const' before 'styles' and move the whole object between our curly braces. Since our styles function is now with the class, within our tag we need to call it as this.styles.container instead of just styles.container.

The last thing we need to do is add the render() method to our class and wrapping our return within it.

After these changes, your file should look like this.

import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default class App extends React.Component{
  render() {
    return (
      <View style={this.styles.container}>
        <Text>Open up App.js to start working on your app!</Text>
        <StatusBar style="auto" />
      </View>
    );
  }

  styles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: '#fff',
      alignItems: 'center',
      justifyContent: 'center',
    },
  });
}
Enter fullscreen mode Exit fullscreen mode

We are going to go ahead and import a few things from the react-native library to display our list of nearby restaurants to the user. From line 3 where it currently says

import { StyleSheet, Text, View } from 'react-native';
Enter fullscreen mode Exit fullscreen mode

We are going to go ahead and add a FlatList and a TouchableOpacity. Line three should then look like this.

import { StyleSheet, Text, View, FlatList, TouchableOpacity } from 'react-native';
Enter fullscreen mode Exit fullscreen mode

A FlatList is an area where we are going to display our list of restaurants and a TouchableOpacity, for all intents and purposes, is just a button that will be used to initialize the search when pressed.

Lastly, we are going to import libraries that will allow us to get the user's location and location permission by adding

import * as Location from 'expo-location';
import * as Permissions from 'expo-permissions';
Enter fullscreen mode Exit fullscreen mode

Creating our FlatList and TouchableOpacity

We are going to go ahead and delete the <Text>Open up App.js to start working on your app!</Text> and revert our app to a completely white screen. Then in the same space between the tag, we are going to add our TouchableOpacity tag Like so.

    <View style={this.styles.container}>
      <TouchableOpacity>
      </TouchableOpacity>
      <StatusBar style="auto" />
    </View>
Enter fullscreen mode Exit fullscreen mode

Between the two touchable opacity tags, we are going to then add a Text tag to the button that says "Search Restaurants".

    <View style={this.styles.container}>
      <TouchableOpacity>
        <Text>Search Restaurants</Text>
      </TouchableOpacity>
      <StatusBar style="auto" />
    </View>
Enter fullscreen mode Exit fullscreen mode

We are also going to style the text tag just a tiny bit by adding style={{backgroundColor: 'grey', color: 'white', padding: 5, marginBottom: 50}} to the Text tag's parameters like so.

<Text style={{backgroundColor: 'grey', color: 'white', padding: 20, marginBottom: 50}}>Search Restaurants</Text>
Enter fullscreen mode Exit fullscreen mode

Now right above our TouchableOpacity, we are going to add our FlatList to display our list of restaurants. Our FlatList can just have a self-closing tag as well like so <FlatList />. We are going to come back to our FlatList tag once we obtain our list of data.

Getting the User's Location

We also need a place to store our list of restaurants and the user location as well as a variable to tell our component whether location permission has been granted. To achieve this we are going to create a state for our component. To do this, we are going to add these lines.

state = { 
  hasLocationPermission: false,
  latitude: 0,
  longitude: 0,
  restaurantList: []
}
Enter fullscreen mode Exit fullscreen mode

Now that we have our button ready to be pushed and state ready to be manipulated, we just need to tell it to grab the list of nearby restaurants when pushed. To do this we are going to need to first get location permission from the user's device and then get their location in coordinates. To achieve this we are going to use the componentDidMount() method which will be called when the app component is first mounted. To do this go ahead and add these lines within your app class.

  componentDidMount() {

  };
Enter fullscreen mode Exit fullscreen mode

We are now going to create a new async method that will first ask the user's location and collect their coordinates accordingly. Right below our componentDidMount method, we are going to go ahead and create the method, getLocationAsync like so.

async getLocationAsync () {

};
Enter fullscreen mode Exit fullscreen mode

Within our method, we are first going to ask what the user's device for permission.

async getLocationAsync () {
    const { status } = await Permissions.askAsync(
      Permissions.LOCATION
    );
  };
Enter fullscreen mode Exit fullscreen mode

and if that permission is granted, we are then going to change our hasLocationPermission and state to true and change our location state to reflect the user's coordinates by using the setState method.

  async getLocationAsync () {
    const { status } = await Permissions.askAsync(
      Permissions.LOCATION
    );
    if (status === 'granted') {
      let location = await Location.getCurrentPositionAsync({});
      this.setState({
        hasLocationPermissions: true,
        latitude: location.coords.latitude,
        longitude: location.coords.longitude,
      });
    } else {
      alert('Location permission not granted');
    }
  };
Enter fullscreen mode Exit fullscreen mode

Then to make sure this method gets called during the first creation of our component go ahead and call the method within our componentDidMount() method like so.

componentDiDMount() {
  this.getLocationAsync();
}
Enter fullscreen mode Exit fullscreen mode

After all this, our entire app class should look like so.

import React from 'react'
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View, FlatList, TouchableOpacity } from 'react-native';
import * as Permissions from 'expo-permissions';
import * as Location from 'expo-location';


export default class App extends React.Component {

  state = { 
    hasLocationPermission: false,
    latitude: 0,
    longitude: 0,
    restaurantList: []
  }

  componentDidMount() {
    this.getLocationAsync();
  }

  async getLocationAsync () {
    const { status } = await Permissions.askAsync(
      Permissions.LOCATION
    );
    if (status === 'granted') {
      let location = await Location.getCurrentPositionAsync({});
      this.setState({
        hasLocationPermissions: true,
        latitude: location.coords.latitude,
        longitude: location.coords.longitude,
      });
    } else {
      alert('Location permission not granted');
    }
  };

  styles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: '#fff',
      alignItems: 'center',
      justifyContent: 'center',
    },
  });

  render() {
    console.log(this.state.latitude, this.state.longitude)
    return (
      <View style={this.styles.container}>
        <FlatList  />
        <TouchableOpacity>
          <Text style={{backgroundColor: 'grey', color: 'white', padding: 20, marginBottom: 50}}>Search Restaurants</Text>
        </TouchableOpacity>
        <StatusBar style="auto" />
      </View>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Tada! now we have our user's location stored safely within our state. We can now use that location to get our list of restaurants nearby in part two!

Discussion (0)

pic
Editor guide