Creating a Local Venue App Using React/Redux with the Foursquare API

Let’s build a Venue Finder app using React and Redux. Why not?

Goals

So, what do we want from our Venue Finder? Well let’s have a think about the kind of features it could have!

We want to…

  • …Search for Venue’s in order of recommendations
  • …Search for type of venues, such as Restaurants, Bars etc
  • …Get Venue’s near you by getting your location!

Here’s what we want to achieve technically…

  • Creating reusable, singular components with React
  • Scale an application with a component architecture
  • Use the Foursquare API to get data of venues based on locations.
  • Manage the state of the application using Redux

Set Up

No need to reinvent the wheel … Let’s initialise our React App by using Create React App. It gives us the necessary boiler plate package and configuration to get started nice and quick, including the capability to view our application on a running local server.

$ npm install -g create-react-app
$ create-react-app venue-finder cd my-app/ npm start
ReactDOM.render(<App />, document.getElementById('root'));

Grabbing The Data Using Fetch

The first thing we want to do is get our Foursquare venue data which, for now will happen on load. To make this easier, we can use a library called Fetch, a polyfill for Javascript that makes AJAX calls easier. I’d like to choose Fetch here because it is becoming a standard for Javascript.

$ yarn add whatwg-fetchimport React, { Component } from 'react'; import logo from './logo.svg'; import 'whatwg-fetch'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to React!</h1> </header> <p className="App-intro"> To get started, edit <code>src/App.js</code> and save to reload. </p> </div> ); } } export default App;
import React, { Component } from 'react'; import 'whatwg-fetch'; class App extends Component { componentDidMount() { const venuesEndpoint = 'https://api.foursquare.com/v2/venues/explore?'; const params = { client_id: CLIENT_ID, //Client ID obtained by getting developer access client_secret: CLIENT_SECRET, //Client Secret obtained by getting developer access limit: 100, //The max number of venues to load query: 'Pubs', //The type of venues we want to query v: '20130619', //The version of the API. ll: '51.5073,0.1276' //The latitude and longitude of Charing Cross, London }; fetch(venuesEndpoint + new URLSearchParams(params), { method: 'GET' }).then(); } render() { return ( <div></div> ); } } export default App;

Update the Component State

We can update the components state using this.setState and updating in the JSX. The power of `setState` is that it detects changes in the virtual DOM, and automatically renders to the DOM if it detects any changes. We don't need to call render() each time we get a change! .. And because it only changes the bits that are different, its it's extremely efficient. This is one of the main advantages of using React.

class App extends Component { constructor() { super(); this.state = { venues: [] }; } //... }
fetch(venuesEndpoint + new URLSearchParams(params), { method: 'GET' }).then(response => response.json()).then(response => { this.setState({venues: response.response.groups[0].items}); //Set the components state });
var setVenueState = this.setState.bind(this);
import React, { Component } from 'react'; import 'whatwg-fetch'; class App extends Component { constructor() { super(); this.state = { venues: [] }; } componentDidMount() { this.getVenues(); } getVenues() { let setVenueState = this.setState.bind(this); const venuesEndpoint = 'https://api.foursquare.com/v2/venues/explore?'; const params = { client_id: CLIENT_ID, client_secret: CLIENT_SECRET, limit: 6, query: 'Pubs', v: '20130619', ll: '51.5073,0.1276' }; fetch(venuesEndpoint + new URLSearchParams(params), { method: 'GET' }).then(response => response.json()).then(response => { setVenueState({venues: response.response.groups[0].items}); }); } render() { return ( <div></div> ); } } export default App;

Rendering to the Template

Now that we have updated our app’s state based on the response, it’s quite easy to update. Within the render function, we add:

render() { var venueList = this.state.venues.map(item => <li>{item.venue.name}</li> ); return ( <ul> {venueList} </ul> ); }

Splitting up the Venue Component

Currently, all of our logic and rendering is in a single file: app.js. This is no good if we want to make our components reusable, and our application scalable in its entirety.

import React, { Component } from 'react'; import 'whatwg-fetch'; export class Venue extends Component { // Make sure we export! render() { return; } }
import { Venue } from './Venue';
render() { return <li>I'm a venue!</li> }
render() { var venueList = this.state.venues.map(item => <Venue /> //The new Venue component ); return ( <ul> {venueList} </ul> ); }

Venue as a Reusable Component

For each instance of Venue that get’s loaded, we want to pass in some data. This is the crux of making a reusable component. In AngularJs for example, this is known as a “directive”, where you have an instance of scope where you can pass in data.

render() { var venueList = this.state.venues.map((item,i) => <Venue key={i} name={item.venue.name}/> //Create a new "name attribute" ); return ( <ul> {venueList} </ul> ); }
render() { return <li>{this.props.name}</li> //pass the name through }

Refactoring Venue as a Stateless Component

React 14 introduced Functional Stateless Components, which means that if we have a simple component without logic, we can get rid of the classes, and the use of this and this.props.

import React, { Component } from 'react'; export const Venue = ({ name }) => <li>{name}</li>; //wow

Add Local Venue Functionality

It’s a bit boring always giving you venue’s in Charing Cross. How about recommended venue’s near your location. Here we pass in the user’s location to Foursquare using the HTML5 navigator api:

getLocation(callback) { navigator.geolocation.getCurrentPosition(function(location) { callback(location.coords.latitude + ',' + location.coords.longitude) }) } getVenues() { let setVenueState = this.setState.bind(this); const venuesEndpoint = 'https://api.foursquare.com/v2/venues/explore?'; this.getLocation(function (latlong) { const params = { client_id: CLIENT_ID, client_secret: CLIENT_SECRET, limit: 100, query: 'Pubs', v: '20130619', ll: latlong }; fetch(venuesEndpoint + new URLSearchParams(params), { method: 'GET' }).then(response => response.json()).then(response => { setVenueState({venues: response.response.groups[0].items}); }); }); }

Wrapping Up — Adding Search Functionality

We nearly have a finished proof of concept! Right now, the app automatically searches for a user. How about we give the user the choice of what they what to look for? What about “Coffee”, “Kebabs”, or anything you like for your area?

import React, { Component } from 'react'; export class Search extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleSubmit = this.handleSubmit.bind(this); this.handleChange = this.handleChange.bind(this); } handleSubmit(event) { event.preventDefault(); this.props.onSubmit(this.state.value); } handleChange(event) { this.setState({value: event.target.value}); } render() { return ( <form onSubmit={this.handleSubmit}> <input id="venueType" onChange={this.handleChange} value={this.state.value} placeholder="search for venues" /> <input type="submit" value="Submit" /> </form> ); } }
import { Search } from './Search';
return ( <div> <Search onSubmit={(value)=>this.handleSubmit(value)}/> <ul> {venueList} </ul> </div> );
handleSubmit(query) { this.getVenues(query); }
getVenues(query) { let setVenueState = this.setState.bind(this); const venuesEndpoint = 'https://api.foursquare.com/v2/venues/explore?'; this.getLocation(function (latlong) { const params = { client_id: CLIENT_ID, client_secret: CLIENT_SECRET, limit: 100, query: query, v: '20130619', ll: latlong }; fetch(venuesEndpoint + new URLSearchParams(params), { method: 'GET' }).then(response => response.json()).then(response => { setVenueState({venues: response.response.groups[0].items}); }); }); }
componentDidMount() { this.getVenues('Pubs'); }

Conclusion

So what has been achieved here?

  • Rendering the app using ReactDOM.Render()
  • Using Fetch for asynchronous HTTP requests to the Foursquare API
  • Setting up React Components with a State
  • Add geolocation using the navigator api
  • Make our components reusable (Venue Component, Search Component)
  • Refactor the simple Venue component to be a stateless component with minimal code
  • Components can communicate with each other using this.props
  • Components execute functions in the parent and pass in parameters, such as when the form submits

Source Code on Github

You can view the source code for this article by clicking on this link. Feel free to make suggestions or fork etc 🙂

Steve is a digital designer and developer, guitarist and keen rock climber based in Brixton, London UK