Foursquare Intersections logo
Explore
Subscribe
Engineering

Getting started with PreactJS

Written by Gareth Paul Jones on Nov 07, 2017 - Read time: 7 min - Read Later

PreactJS was developed with the goal of providing high performance, memory efficiency and close compatibility with React with an aim to keeping footprint as minimal as possible. It provides the thinnest possible Virtual DOM abstraction on top of the DOM.

The benefits of PreactJS only grow when you integrate Foursquare's Places API into your high-performing web app; by adding location intelligence, you can instantly get access to real-world information. Let's see how two technologies complement each other.

Here is what we'll be building today.

PreactJS Foursquare Developers screen

Local Setup

Assuming that you already have Node and NPM installed on your machine. We'll install the command line tool.

npm i -g preact-cli@latest

Once installed, let's create our our first app.

preact create default preact-foursquare

Now let's get the project up and running.

cd preact-foursquare
preact watch

When preact-cli is done building files, we can point our browser to http://0.0.0.0:8080 or a localhost url provided by npm run start.

sample of PreactJS screenshot

Let's Look At Code

At this we have a basic Preact app where we can make changes.

Open index.js in your favorite code editor — it should look something like the following:

import './style';
import { h } from 'preact';
import { Router } from 'preact-router';
import Header from './components/header';
import Home from './routes/home';
import Profile from './routes/profile';
export default () => (
 

<router> <home path="/"> <profile path="/profile/" user="me"> <profile path="/profile/:user"> </profile></profile></home></router>

);

Now, let's open Home component inside ./routes/home and change line 9.

// From 

This is the Home component.

// To

This is a spectacular component.

Save this file and head over to http://0.0.0.0:8080 or chosen URL.

screenshot of PreactJS usage

Add Foursquare Places API

Let's now add a new Component in our app to get venues.

Earlier this year we launched a basic react plugin react-foursquare . We can install this plugin via the following command:

npm i react-foursquare

Create a folder called venues inside routes . Then create a file index.js inside the venues folder. We are going to write a component which will fetch venues from Foursquare's Places API.

import { h, Component } from 'preact';
var foursquare = require('react-foursquare')({
  clientID: '<insert_id_here>',
  clientSecret: '<insert_secret_here>'
});</insert_secret_here></insert_id_here>
var params = {
  "ll": "37.7749,-122.4194",
  "query": 'Blue Bottle'
};
export default class Venues extends Component {
  state = {
    items: []
  };
componentDidMount() {
    foursquare.venues.getVenues(params)
      .then(res=> {
        this.setState({ items: res.response.venues });
      });
  }
render() {
    return (
        
Items:
{ this.state.items.map(item=> { return
{item.name}
}) }

) } }

The code above queries the Foursquare Places VenueSearch API and returns results for the query bluebottle nearby the lat/long 37.7749,-122.4194.

Now that our component is ready. We will hook it up with routes and add a link in the header bar. Open app.js which is in the components directory of the project and import the Venues component which we just created.

import { h, Component } from 'preact';
import { Router } from 'preact-router';
import Header from './header';
import Home from '../routes/home';
import Profile from '../routes/profile';
import Venues from '../routes/venues';
// import Home from 'async!../routes/home';
// import Profile from 'async!../routes/profile';
export default class App extends Component {
 /** Gets fired when the route changes.
  * @param {Object} event  "change" event from [preact-router](http://git.io/preact-router)
  * @param {string} event.url The newly routed URL
  */
 handleRoute = e => {
  this.currentUrl = e.url;
 };
render() {
  return (
   

<router onchange="{this.handleRoute}"> <home path="/"> <profile path="/profile/" user="me"> <profile path="/profile/:user"> <venues path="/venues"> </venues></profile></profile></home></router>

); } }

Then — open ./components/header/index.js and add new Link tag.

import { h, Component } from 'preact';
import { Link } from 'preact-router/match';
import style from './style';
export default class Header extends Component {
 render() {
  return (
   

Preact App

 

<link activeclassname="{style.active}" href="/"/>

Home

<link activeclassname="{style.active}" href="/profile"/>

Me

<link activeclassname="{style.active}" href="/profile/john"/>

John

<link activeclassname="active" href="/venues"/>

Venues ); } }

Now, let's visit our newly created component http://0.0.0.0:8080/venues. Your page should look something like this.

screenshot of a PreactJS test

Now that we have a skeleton setup to access the Places API we can make some additional changes to utilize more data from the API.

To start we need to modify app.js within src/components . This allows us to route traffic directly to http://0.0.0.0:8080/. We can additionally remove some redundant code src/routes/home and src/routes/profiles.

import { h, Component } from 'preact';
import { Router } from 'preact-router';
import Header from './header';
import Footer from './footer';
import Venues from '../routes/venues';
export default class App extends Component {
 /** Gets fired when the route changes.
  * @param {Object} event  "change" event from [preact-router](http://git.io/preact-router)
  * @param {string} event.url The newly routed URL
  */
 handleRoute = e => {
  this.currentUrl = e.url;
 };
render() {
  return (
   
<router onchange="{this.handleRoute}"> <venues path="/"> </venues></router>
 

 

); } }

Once we've done this, let's now add some more data to our detail page and add two search boxes.

Modify the src/routes/venues/index.js as follows:

import { h, Component } from 'preact';
import style from './style';
var foursquare = require('react-foursquare')({
  clientID: '',
  clientSecret: ''
});
export default class Venues extends Component {
  state = {
    items: [],
    query: '',
    near: 'San Francisco, CA'
  };
componentDidMount() {
    this.fetchVenues();
  }
fetchVenues = () => {
    var params = {
      "near": this.state.near,
      "intent": 'browse',
      'query': this.state.query
    };
    foursquare.venues.recommendations(params)
      .then(res=> {
        console.log(res)
        this.setState({ items: res.response.group.results });
      })
  }
setQuery = e => {
      this.setState({ query: e.target.value });
  }
  setLocation = e => {
      this.setState({ near: e.target.value });
  }
render() {
    return (
        
Find | Near Search
{ this.state.items.map(item=> { if (item.photo) { var photo_url = item.photo.prefix + '400x400' + item.photo.suffix; var ratingColor = 'background-color: #' + item.venue.ratingColor; var category_icon = item.venue.categories[0].icon.prefix + '100' + item.venue.categories[0].icon.suffix; var venue_url = "https://foursquare.com/v/" + item.venue.id; return (

{item.venue.name}

{item.venue.location.address}, {item.venue.location.city}

{item.venue.rating}
) } }) }

) } }

There is a quite a lot going on here, so let's break this down.

Functions

  • fetchVenues — this pulls venues using the Places API.
  • setQuery — sets the query utilized by the Places API.
  • setLocation — sets the location for the Places API to use.

Render

Render now includes some more details about venues.

  • Name
  • Address
  • Rating
  • Category

Now that we have all this data about a given venue, let's add some CSS to display these details. We do this in src/routes/venues/style.css.

.header {
 position: fixed;
 left: 0;
 top: 40px;
 width: 100%;
 height: 86px;
 padding: 0;
 background: #6740B4;
 box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
 z-index: 50;
}
.search {
  position: relative;
  width: 700px;
  height: 40px;
  z-index: 15;
  top: 119px;;
  left: 50%;
  margin: -100px 0 0 -400px;
  background: #FAFAFA;
  border-radius: 5px;
  padding:5px;
  padding-top:7px;
}
.search label {
  color: #666;
  margin-right: 12px;
  margin-left: 12px;
  font-weight: 700;
}
.search input {
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  border: 1px solid transparent;
  font-size: 18px;
  background-color: #FAFAFA;
}
.search input::placeholder{
  color:#ACABAB;
}
.search input:focus {
  outline:none;
}
.query {
  width:280px;
}
.near {
  width: 180px;
}
.find {
  height: 40px;
  position: absolute;
  right: 0px;
  top: 0;
  border: 1px solid transparent;
  border-top-right-radius: 3px;
  border-bottom-right-radius: 3px;
  background-color: #967CCA;
  font-size: 1.2em;
  color:white;
  text-transform: uppercase;
  border: none;
  outline:none
}
.bar {
  font-size: 20px;
  color: #666;
  margin-right:5px;
}
.container {
    padding-right: 15px;
    padding-left: 15px;
    margin-right: auto;
    margin-left: auto;
    margin-top: 120px;
    height: auto;
}
.row {
}
.box {
  margin:20px;
  background-color: #F5F3F0;
  margin-bottom: 20px;
  box-shadow: 5px 5px 25px 0 rgba(46,61,73,.2);
  border-radius: .375rem;
  transition: all .3s ease;
  float: left;
  width: 350px;
  height: 350px;
  max-width: 350px;
  max-height: 350px;
  position:relative;
  float:left;
  overflow: hidden;
  animation: fade .25s;
}
@keyframes fade {
  from {opacity: 0;}
    to {opacity: 1;}
}
.box img {
  margin-left: auto;
 margin-right: auto;
 display: block;
  border-radius: 2px;
}
.wrap {
  position:absolute;
  width:100%;
  height:100px;
  bottom:0;
  left:0;
  background-color:#F1F1F1;
}
.venue_name {
  position: absolute;
  font-weight: 900;
  font-size:1.2em;
  padding-top:10px;
  padding-left: 10px;
  color: black;
  height: 55px;
  width:350px;
  top:0;
  left:0;
}
.venue_address {
  position: absolute;
  font-size:13px;
  padding-top:10px;
  padding-left: 10px;
  color: black;
  width:350px;
  top:40px;
  left:0;
}
.rating {
  position: absolute;
  font-weight: 200px;
  height:50px;
  width:50px;
  border-radius: 200px;
  right: 0;
  bottom:0;
  text-align: center;
  vertical-align: middle;
  line-height: 50px;
  margin-right:10px;
  margin-bottom:10px;
  color:white;
}
.category {
  position: absolute;
  font-weight: 200px;
  height: 30px;
  width: 30px;
  border-radius: 200px;
  bottom: 15px;
  text-align: center;
  vertical-align: middle;
  line-height: 50px;
  margin-right: 10px;
  margin-bottom: 10px;
  right: 68px;
}
.category_icon {
  background-color: #666;
  width: 40px;
  height: 40px;
}

After making these changes we can now head over to our browser to see the changes that have propagated.

completed PreactJS project for Foursquare Developers

If you ever run into a snag with the Foursquare API, please feel free visit the Foursquare for Developers website for documentation on the endpoints.

Interested in using Foursquare's location intelligence for your business? Explore our products and solutions on the Foursquare for Enterprise website.

Now, go forth and develop! We look forward to seeing what you build!

Subscribe

Follow Gareth Paul Jones

Getting started with PreactJS

Read Later

Pardot response heading