React Native Tutorial - Yelp Clone

Turbo 360

In this 18-part series, we go into some more intermediate and advanced React Native topics and work on building out the main Map Section and Search on a Yelp Clone Application. We start the series by setting up React Native Maps, and plot a random location on the map. We then use a data set of restaurants in New York City to seed a Mongo DB database with 20,000 restaurant locations. Once we have our database seeded, we create the ability on the mobile side to drag the map and automatically send the post drag coordinates of our React Native Map to the server via fetch. Based on these map coordinates, we can perform a geospatial query and return all the matching locations in the view of our map to the React Native Application where they are then plotted. Additionally, we learn to use the PanResponder API to create a view that acts as an overlay and displays additional data about these restaurants. The restaurants in our overlay are always synced up with our map so when we drag the map and re-query our restaurants resort automatically based on map position (Just like in the Yelp App).
Key Topics Covered

  • React Native Maps
  • MongoDB and Geospatial Queries
  • Creating Network Requests with Fetch and Handling Responses
  • Express and Mongoose
  • React Native Pan Responder
  • React Native Animations and Interpolations


Project Setup

Zoom Button - 0:00
As we have messed with in previous videos latitudeDelta and longitudeDelta give us a more zoomed in or zoomed out view. What were are going to do is add a plus and minus that will affect these values. Also after changing this value we will requery for locations. We start this by moving the lat and long into the state.

Creating the buttons - 5:45
We create two TouchableOpacity buttons on our map one being a plus and one beings a minus. We style these buttons to put them onto the right side.

Zoom function - 14:00
On press we want our button to zoom in or out so we create a general function that takes the sign and performs the operation depending on it. We will increase or decrease our deltas inside of the region depending on the sign. On the asynchronous call back we want to getRestaurants again and get rid of the button.

Project Structure

Building File Structure - 0:00
Right now we don’t have anywhere to keep our JavaScript files so create a source directory and in there have a components, config. In components have a screens, containers, and view.

Main Screen - 1:55
In screens create the index file and a main file. Put in the basic stuff to make sure it is rendering. We delete useless stuff from the app.js, import main, and render it.

Tab Bar - 7:15
We are starting with the tab bar to get it out of the way. We install react navigation and import TabNavigator. We only want the search tab so we just copy and paste the same screen across all the tabs.

Maps Piece - 10:25
The map is going to be a component so we start by creating it and installing react native maps. After making a dummy text render for maps we put that into the main to make sure it works. We then start looking into react native maps. In the next part we will go into setting up react native maps.

React Native Maps

Setting up Google Maps Configuration - 0:00
If you are using expo you can import the mapView from expo. If not you are going to have to install cocoapods as it is a dependency manager for xcode. Once installed go to the clone target with yelpCode.xcodeproj. Use the documentation to paste in what needs to be in the Podfile. We now need to create an API key

Setting up Google Maps - 7:30
We need to get our API key so go to Google cloud and get the API key. Then continue following the react-native-maps documentation to add the key. Also make the height and width of the map 100% so it has some style. We are using Apple Maps as a fallback for now. We also change the latitude and longitude to default to New York.

Showing Locations on the Map

Render Markers - 0:00
If you do onRegionChangeComplete and then give it a callback you are able to get the delta of change and the final latitude and longitude. In our constructor we make a marker array. We then go to our render and loop over them. The latitude and longitude will be a pair. Title and description are just strings. Be careful with the child imports. We put a marker on WeWork and a marker on Penn Station.

Get Coordinates on Server - 12:30
We we were logging onRegionChangeComplete we want to use that to set state of the current view to the region. The lat and long deltas are the size of the screen.

Implementing Seed Data

Pre Populate Database - 0:00
We can find some data online about some restaurants so we want to import this to our hosted database. To do this we make a text file and use the import we can find on mLab to import the text file. Go to your collections in mLab and check and it should have a lot of different points. We then test one of the points to make sure it works.

Querying Data

Get Resturants - 0:00
In the maps component make a function called get resturants that does a fetch request on a url that we define in the config. We make this function be called after onRegionChangeComplete. We install the query string module in order to help us add a region to our fetch. In the next video we will use this information to query the database.

Returning Data to the App

Interfacing With Database - 0:00
We install Mongoose in order to better interface with Mongo. Mongoose is an object relational mapper. We make a models directory and create a restaurant model.

Server Query - 9:20
We go to the server api and require those models where we have our api routes. We then get our model with req.params and findOne of that model based on the params.

Returning to App - 18:30
When the response is returned we will set state to the response we are handling. We need to make the returned destination fit the look of our state. In the next part we are going to query by location.

Geospatial Queries

Construct Coordinates - 0:00
We need to construct a polygon for our geoquery which essentially creates a rectangle of our screen. Each coordinate is a different combination of the stuff sent in our query.

Actual Query - 15:25
We then find our model where location is within our geo query.

Displaying Locations 26:15
We change up our get restaurants to go for each on the location array returned and set the state with them.

Zooming In and Out

Fixing Coordinates - 0:00
Right now latitude and longitude is the center so we are only getting the top right quadrant. Once this is fixed the screen fills up with red pins.

Become Less Taxing - 7:25
We are returning everything right now which is way too taxing for the client. We are going to change this by only passing back one hundred restaurants. We also zoomed in our map.

UI and Performance Enhancements

Redo Search in Area - 0:00
Searching every time the map changes is not good performance. Instead we are going to create a button to redo the query. We add a button and do an onpress to run getResturants which no longer takes a region as we moved that into the state when we change location.

Styling Button - 10:30
We change the button to TouchableOpacity as we are more familiar with it. We also put the TouchableOpacity into its own view to be able to not accidentally align the stuff on the map. We also need to make sure it disappears when we refresh and when we move it becomes true. We also add a activity indicator to show when we are performing our query.

Showing Restaurant Info

Menu of Restaurants - 0:00
We create a new container component called restaurants. We create a basic look and then put it into the main screen. We also create a restaurant view that is a stateless component. We then render this in our restaurant component. We build up our restaurant view with some dummy data. We also add in react-native-icons for our stars.

Sorting Restaurants by Rating

FlatList - 0:00
Right now we are statically rendering a bunch in the restaurant container so now we are going to use a flatList

Adding Map with Restaurants - 3:45
We add restaurants and map to the same screen but then the map takes up the whole screen. So we use flex 1 on each in order to take half of the screen for each.

Adjusting Schema - 8:25
We need to update our schema so our document matches our schema. To update we make an updateSeedData route that finds one and updates with some default data. However, updating one isn’t what we really need so we find everything instead and loop over them updating one at a time.

Sorting Restaurants - 36:25
In our schema we also added a rating to sort by so when we get them we sort by rating. This spreads out our pins that have thus far been pretty scrunched.

Syncing Data Between Components

State of Restaurants in Parents - 0:00
In order to have the list update when the places are refreshed we are going to have to keep the state of the restaurants in the parents so that it can be transferred across the components. So we move the restaurants up and pass the restaurants as a prop to the map component. We also do the same with our restaurants component. We also pass this to our restaurant view which we use to fill our data. We also push our stars into an array to render the stars since we only have it as a number.

Draggable Map

Collapsing Menu - 0:00
We need a system that can detect a touch event and act on that touch event. To do this we import PanResponder and animated into our Restaurant component. When the component mounts we create a PanResponder. The way PanResponder works in React Native is you make the components in the view an animated component and it will then be able to work with the animated values you set in the PanResponder.

Make Map Whole Screen - 11:05
We want to make the map the whole screen and then have the restaurants to sit on top. Right now they are a flex of one so we give it absolute positioning it covers the whole screen.

Animation - 13:30
We want to give the restaurants a bar we can grab so we make it visually have a bar. We then drop the PanHandlers into the view. PanHandler can respond to a bunch of different events and change values so we create values for our translation of the the menu.

Using PanResponder

Constraining Drag- 0:00
Where we are setting or x to the pan instead we set x to 0. However, we are able to drag it above the screen and when we grab it a second time it shoots back up. We set the y in PanResponderGrant to be 0 and give it an offset so that is doesn’t hop. You also need to flatten the offset on release. Our FlatList also needs a height or it will break as we overlay the two.

Animation Improvements

Moving Map Screen - 0:00
Because of what we did the restaurant screen overlays the whole screen and we can no longer drag the map. We need to make sure to move the whole view instead of just visually moving it. To do this we move the the panResponder up a level and control it from there.

Taking Out of State - 8:45
We take our variables out of state to improve performance.

Improving UI - 11:20
We did this UI more for demonstration so now we are going to make it more of a normal UI. We were using red for debugging so we change it to follow the look of the actual Yelp app.

Sitting on Top of Tab Navigator - 27:00
We want to make it start at the bottom so we get the dimensions and subtract 400. You should be getting this dynamically though which is a good challenge to figure out.

Interpolation

Constraining to on Screen - 0:00
Right now it is going off the bottom and top of the screen so we use a JSON object that uses fadeAnim interpolate. The hard part is getting the input range and output range. To do this we experiment with a movable range constant and clamp that value so it does not escape it.

Zoom In and Out Buttons

Zoom Button - 0:00
As we have messed with in previous videos latitudeDelta and longitudeDelta give us a more zoomed in or zoomed out view. What were are going to do is add a plus and minus that will affect these values. Also after changing this value we will requery for locations. We start this by moving the lat and long into the state.

Creating the buttons - 5:45
We create two TouchableOpacity buttons on our map one being a plus and one beings a minus. We style these buttons to put them onto the right side.

Zoom function - 14:00
On press we want our button to zoom in or out so we create a general function that takes the sign and performs the operation depending on it. We will increase or decrease our deltas inside of the region depending on the sign. On the asynchronous call back we want to getRestaurants again and get rid of the button.

Membership Options