How To Add Location Services To A React App
You will need Node half-dozen+ and npx installed on your motorcar.
Today, almost all of the states rely on map applications for directions, distances and local information… Now, nosotros even accept the ability to share our alive location with friends, but imagine a scenario where a group of three friends are trying to meet at a item location, each one of the friends needs to send a link to the others for them to know where they are.
In this article, we are going to utilise Pusher Channels to create a React application that allows you to see the location of your friends in realtime when they are online on the app. Past the cease of this commodity, you should have an application that looks similar this:
Prerequisites
To follow through this tutorial, y'all'll need the following:
- Node >= half dozen installed on your auto
- npm >= 5.2 installed on your car
- npx installed on your automobile
Getting started
To go started, create a new React application by running this command:
npx create-react-app pusher-react-location
This creates a starter React project in a folder titled pusher-react-location
. To see the demo application at work, become to your terminal and run the command:
cd pusher-react-location npm start
This serves the React application. Navigate your browser to http://locahost:3000
and you should get a view that looks similar this:
Building the backend server
The backend server of our awarding will have the following functionality:
- Sharing users' locations
- Authenticating new users on the presence channel
Create a /server
binder in your project:
mkdir server cd server
Install the Node modules that we will need to power the backend server:
npm init -y npm install limited trunk-parser pusher
-
express
will power the web server -
torso-parser
to handle incoming requests -
pusher
to add realtime functionality and online presence
Afterwards, create a server.js
file in the server/
directory:
affect server.js
Edit the server.js
file to wait as follows:
// server/server.js const express = require ( 'express' ) const bodyParser = require ( 'body-parser' ) const Pusher = crave ( 'pusher' ) ; // create a express awarding const app = limited ( ) ; // initialize pusher let pusher = new Pusher ( { appId: 'PUSHER_APP_ID' , key: 'PUSHER_APP_KEY' , secret: 'PUSHER_APP_SECRET' , cluster: 'PUSHER_APP_CLUSTER' , encrypted: true } ) ; app. apply (bodyParser. json ( ) ) ; app. use (bodyParser. urlencoded ( { extended: imitation } ) ) ; // to Permit CORS app. use ( ( req, res, next ) => { res. header ( 'Access-Control-Allow-Origin' , '*' ) ; res. header ( 'Access-Control-Allow-Headers' , 'Origin, X-Requested-With, Content-Type, Take' ) ; side by side ( ) ; } ) ; [ ... ]
We include the necessary JavaScript libraries and then create a new Pusher object using your
Pusher application credentials.
To obtain your Pusher credentials, create a new account here. Afterwards, you'll be redirected to your Pusher dashboard. Get alee and create a new project, obtain your
PUSHER_APP_ID
,PUSHER_APP_KEY
,PUSHER_APP_SECRET
,PUSHER_APP_CLUSTER
and add them to yourserver.js
file.
Later on, we specify some application middleware to handle incoming requests. The backend server volition take two routes:
-
/pusher/auth
- handles requests to cosign users joining the presence channel -
/update-location
- handles requests to trigger an issue when a user updates their location.
With Pusher, when a new customer tries to bring together a presence channel, a POST
request is beginning fabricated to authenticate the new client. In this case, we create a random string to identify the client and this makes up the presenceData
object. The presenceData
, channel
and socketId
are then passed to Pusher to cosign the client.
The /update-location
road accepts the incoming data and so triggers a location-update
event to the presence-channel
.
In after parts of the commodity, we volition see how the channel is created in our React application
Add the code beneath to your server/server.js
file:
// server/server.js [ ... ] app. post ( '/pusher/auth' , ( req, res ) => { let socketId = req.body.socket_id; let aqueduct = req.body.channel_name; random_string = Math. random ( ) . toString ( 36 ) . supplant ( / [^a-z]+ / g , '' ) . substr ( 0 , 5 ) ; let presenceData = { user_id: random_string, user_info: { username: '@' + random_string, } } ; allow auth = pusher. authenticate (socketId, channel, presenceData) ; res. transport (auth) ; } ) ; app. post ( '/update-location' , ( req, res ) => { // trigger a new post issue via pusher pusher. trigger ( 'presence-channel' , 'location-update' , { 'username' : req.body.username, 'location' : req.body.location } ) res. json ( { 'status' : 200 } ) ; } ) ; let port = 3128 ; app. heed (port) ; console. log ( 'listening' ) ;
At present that the backend server is created, you tin can run it by inbound the command:
node server.js
Now, permit's wait at how to build the rest of the application.
Creating the interface
Beginning of all, we need to get a simple map interface for the application and to do this, let's utilize Google Maps JavaScript API. Follow this guide to obtain your Google Maps API key which nosotros volition use later in this awarding.
Installing necessary packages
To add all functionality to our awarding, we'll need to install the following packages:
- google-map-react - to use the Google Maps JavaScript API with react
- pusher-js - to enable realtime functionality with Pusher
- axios - to make POST requests to our backend server
- react-toastify - to notify users when new users are online or go offline
To install, get to the root folder of your react application and run the following in your last:
npm install google-map-react pusher-js axios react-toastify
Displaying the map
To see it at piece of work in your application, edit your src/App.js
file to look like this:
// src/App.js import React, { Component } from 'react' ; import GoogleMap from 'google-map-react' ; const mapStyles = { width: '100%' , height: '100%' } const markerStyle = { pinnacle: '50px' , width: '50px' , marginTop: '-50px' } const imgStyle = { height: '100%' } const Mark = ( { title } ) => ( <div fashion= {markerStyle} > <img way= {imgStyle} src= "https://res.cloudinary.com/og-tech/image/upload/s--OpSJXuvZ--/v1545236805/map-marker_hfipes.png" alt= {title} / > <h3> {title} < /h3> < /div> ) ; class App extends Component { render ( ) { render ( <div > <GoogleMap fashion= {mapStyles} bootstrapURLKeys= { { primal: 'GOOGLE_MAPS_API_KEY' } } eye= { { lat: 5.6219868 , lng: - 0.1733074 } } zoom= { xiv } > <Marker championship= { 'Current Location' } lat= { 5.6219868 } lng= { - 0.1733074 } > < /Marking> < /GoogleMap> < /div> ) } } export default App;
In the App.js
file, we defined the eye
of the map and a single marking which will represent the location of the user when they open the application.
Note: Call back to add together your
GOOGLE_MAPS_API_KEY
which you can obtain hither.
Now, when y'all run the application and navigate to localhost:3000
in your browser you get the view below:
Currently, the heart of the map and the user's pin are hard-coded into the application. Let's look at how to make these dynamic and brandish the user's location and the location of other users signed in to the application.
Displaying online friends locations in realtime with Pusher
Now let's update the App.js
to include the functionality. First, nosotros need to add states to our component that volition track:
- The map middle
- Users online
- Username of the current user
- Location for other online users
Update the App.js
file so that your constructor will wait similar this:
// src/App.js [ ... ] import axios from 'axios' ; import Pusher from 'pusher-js' ; import { ToastContainer, toast } from 'react-toastify' ; import 'react-toastify/dist/ReactToastify.css' ; class App extends Component { constructor ( props ) { super (props) this .state = { center: { lat: 5.6219868 , lng: - 0.23223 } , locations: { } , users_online: [ ] , current_user: '' } } [ ... ] }
We so create a new Pusher object in the componentDidMount()
lifecycle method by specifying the PUSHER_APP_KEY
, PUSHER_APP_CLUSTER
and the authEndpoint
created on our backend server before in the article. Afterwards, nosotros subscribe to the presence-channel
and and then bind the channel to listen for four events:
-
pusher:subscription_succeeded
upshot that is triggered from the backend server when a user successfully subscribes to a presence channel . -
location-update
event which is triggered when another user's location is updated. -
pusher:member_removed
consequence that is triggered when some other user goes offline. -
pusher:member_added
event that is triggered when a new user comes online.
// src/App.js [ ... ] class App extends Component { [ ... ] componentDidMount ( ) { let pusher = new Pusher ( 'PUSHER_APP_KEY' , { authEndpoint: "http://localhost:3128/pusher/auth" , cluster: "mt1" } ) this .presenceChannel = pusher. subscribe ( 'presence-aqueduct' ) ; this . presenceChannel . bind ( 'pusher:subscription_succeeded' , members => { this . setState ( { users_online: members.members, current_user: members.myID } ) ; this . getLocation ( ) ; this . notify ( ) ; } ) this . presenceChannel . bind ( 'location-update' , trunk => { this . setState ( ( prevState, props ) => { const newState = { ...prevState } newState.locations[ ` ${body.username} ` ] = body.location; return newState; } ) ; } ) ; this . presenceChannel . bind ( 'pusher:member_removed' , member => { this . setState ( ( prevState, props ) => { const newState = { ...prevState } ; // remove member location in one case they go offline delete newState.locations[ ` ${member.id} ` ] ; // delete member from the listing of online users delete newState.users_online[ ` ${fellow member.id} ` ] ; return newState; } ) this . notify ( ) } ) this . presenceChannel . bind ( 'pusher:member_added' , member => { this . notify ( ) ; } ) } [ ... ] }
Notice that nosotros called a notify()
method on our Pusher events. Add the function to your App.js
file like below:
// src/App.js class App extends Component { [ ... ] notify = ( ) => toast ( ` Users online : ${Object. keys ( this .state.users_online) .length} ` , { position: "top-right" , autoClose: 3000 , hideProgressBar: fake , closeOnClick: true , pauseOnHover: truthful , draggable: true , type: 'info' } ) ; [ ... ] }
Nosotros besides chosen a getLocation()
method in the componentDidMount()
. This role is responsible for fetching the location of the user from the browser. Let's have a look at how this works. Add together the getLocation()
role to your App.js
file:
// src/App.js course App extends Component { [ ... ] getLocation = ( ) => { if ( "geolocation" in navigator) { navigator.geolocation. watchPosition ( position => { let location = { lat: position.coords.latitude, lng: position.coords.longitude } ; this . setState ( ( prevState, props ) => { let newState = { ...prevState } ; newState.middle = location; newState.locations[ ` ${prevState.current_user} ` ] = location; render newState; } ) ; axios. post ( "http://localhost:3128/update-location" , { username: this .state.current_user, location: location } ) . then ( res => { if (res.status === 200 ) { console. log ( "new location updated successfully" ) ; } } ) ; } ) } else { alarm ( "Pitiful, geolocation is non bachelor on your device. You need that to use this app" ) ; } } [ ... ] }
The getLocation()
method first checks if the application tin can access the geolocation belongings of the browser and alerts the user if it can't. The navigator.geolocation.watchPosition()
method gets the users' location as the user moves so updates the component states with the most up to date location of the user. Afterwards, a request is made to the backend server to trigger a location-update
event so that other signed in users can exist notified with the latest location.
Finally, to show all locations of online users, let's update the render()
function of the component to look like this:
// src/App.js [ ... ] class App extends Component { [ ... ] render ( ) { let locationMarkers = Object. keys ( this .country.locations) . map ( ( username, id ) => { return ( <Marker central= {id} title= { ` ${username === this .state.current_user ? 'My location' : username + "'due south location" } ` } lat= { this .country.locations[ ` ${username} ` ] .lat} lng= { this .state.locations[ ` ${username} ` ] .lng} > < /Marker> ) ; } ) ; return ( <div > <GoogleMap style= {mapStyles} bootstrapURLKeys= { { key: 'GOOGLE_MAPS_API_KEY' } } center= { this .state.center} zoom= { 14 } > {locationMarkers} < /GoogleMap> < /div> ) } [ ... ] }
locationMarkers
creates a list of Marker
'due south for each of the online users. This will give the user a perspective of where his other online friends are.
Now, reload the application and navigate to localhost:3000
. Your application should work similar this when multiple users are online:
Conclusion
In this tutorial, we saw how to use Pusher Channels, Google Maps and React to build a live map with online presence that lets you know where your friends online are. This tutorial is ane of the many means you tin can use Pusher Channels in the production y'all build. Feel free to use the concepts shared hither in your own awarding. Here'due south a link to the GitHub repository.
How To Add Location Services To A React App,
Source: https://pusher.com/tutorials/live-map-react/
Posted by: wadebuthow.blogspot.com
0 Response to "How To Add Location Services To A React App"
Post a Comment