Rendering Different React Components Depending on the User’s Geographic Location

Or how to choose between Google Maps and Baidu Maps when you need to render a map in your React application.

David Barral
Trabe
5 min readMay 11, 2020

--

Photo by Jamie Street on Unsplash

In her latest posts, my teammate Clara Dopico has told us the problems she faced when she needed to use maps in an application, which was meant to be used across the globe, due to the ban of Google Maps in China. To overcome this limitation she used an alternative service: Baidu Maps.

Now that we know how to add Baidu Maps to an application without learning Chinese, and mastered the quirks of the react-baidu-maps library, the missing piece of the puzzle is knowing when to use them. Ideally we want to offer a default experience based on Google Maps and fallback to Baidu Maps just for Chinese users.

The solution is to geolocate our users to know their country of origin, and based on that render different components: a Baidu Map for the Chinese user, and a Google Map for anyone else.

There are several ways to do this: we can use the standard geolocation API in the browser or some geolocation service based on the user’s IP address.

Browser geolocation vs IP address geolocation

The Geolocation interface represents an object able to programmatically obtain the position of the device. It gives Web content access to the location of the device. This allows a Web site or app to offer customized results based on the user's location.

When you ask the browser for its location, the user will be prompted to allow it.

If the user does not allow it, there’s nothing you can do about it. If the user allows it, the Geolocation API will give you the approximate position of the user using in a GeolocationPosition object. The info available in this object will depend on your device capabilities (I edited some data for privacy reasons, but in my laptop with my ISP it’s fairly accurate).

{
coords: {
accuracy: 34
altitude: null
altitudeAccuracy: null
heading: null
latitude: 99.9999999
longitude: -88.8888888
speed: null
},
timestamp: 1589108979874
}

Longitude and latitude coordinates are not a country code so we need to combine this information with some other service that transforms those coordinates into a real world address. Something like the Google Maps Geocoding API.

There’s a catch though! If you want to know if the user is in China you can’t use the Google Geocoding API. It’s part of the Maps API and it’s blocked! 🤦🏽‍♀️.

You are left with two options: 1) use a geocoding service available worldwide, or 2) use some IP address based service.

If we go down the IP address geolocation route, there are several paid and free services. In this story we will use geolocation-db.com (known before as geoip-db.com, but it seems that they had to change their domain due to some trademark claim 🤷🏽‍♀️). This service is free and allows unlimited requests per day. It’s not clear if they have some kind of rate limiting in place but I suppose they do.

To get started, just sign up and get an API key.

The service provides an endpoint that, based on your request’s origin IP address, will return your location info in JSON format (again I edited some data for privacy reasons, but it’s also fairly accurate, I am in Spain 😉):

{
"country_code": "ES",
"country_name": "Spain",
"city": "A Coru\u00f1a",
"postal": "1500",
"latitude": 99.999,
"longitude":-88.888,
"IPv4": "150.150.150.150",
"state”: ”A Coru\u00f1a”
}

You can expect this kind of API from every similar service.

Now that we have defined our geolocation mechanisms, let’s see how we can use this stuff in a React app.

Using a React Hook to detect the user location

Our solution will be based on a useLocation Hook. This Hook will locate somehow the user and return the geographic information that allows us to know from which country is accessing our application.

This Hook tries to locate the user on mount, and has a basic state management to let the clients know if it’s still trying to locate the user or if something went wrong. There is no retry mechanism but it could be possible to add one.

Notice that this Hook relies on a configurable detector function in order to allow those different detection mechanism we explained earlier to be dynamically configurable.

Once in place (using a mockDetector for the time being) we can code our app. We expect useLocation to return a country code as location. Using this info we can make choices like rendering a Baidu Map component in China instead of a Google Map.

If you prefer, you can either use a HoC or a render prop. Just use the Hook to code the alternative component:

Now, let’s try to build the real (and useful) detectors to use with the Hook.

Gelocation-db.com detector

Our detector function issues a request to the service API, does some response and error handling, and gets the country_code from the JSON. Very simple.

To use it, just pass it to the Hook: useLocation(geolocationDb(GEODB_API_KEY)).

Geolocation API detector

As I said before, you can get the user coordinates using the browser’s Geolocation API, but that’s not a country. We need to transform those coordinates into an address. For this story we’ll stick with the Google Maps Geocoding API, just to illustrate the technique. In a real life scenario involving China this wouldn’t be an option.

The detector function could look like this if we add some error handling to the mix: first get the coordinates, then try to get the address using Google Maps, then extract the country code (it’s a bit cumbersome because of the Maps API response format 😥).

To use it, just pass it to the Hook: useLocation(browserLocation(GOOGLE_MAPS_API_KEY)).

Summing up

When rendering React components conditionally, based on some “external” information, we always use the same pattern: we put in place a Hook, a HoC or a render function that provides the info needed to choose between components (render based on a media or a component query, on some theming or whatever comes to your mind). Conditional rendering based on geolocation is no different.

UX wise is very important to offer great experiences, having suitable fallbacks when the main UI is limited, or offering alternatives tailored to the target audience. Geographic location can be a factor when deciding what to render. To overcome the ban of Google services in China we built a Hook to geolocate the user and render different Map UIs. We could have also used this hook to render different maps based on usage preferences (Google Maps is not the top dog on every country).

To locate an user you can use an IP address locating service or the browser’s Geolocation API (in combination with some geocoding API). Geographically locating the user is not always possible. They can block the browser’s Geolocation API or use some form of VPN to change their traffic’s origin to an IP from a different location. Locate the user only when it’s fair and useful and always be honest and open about it. If your application gives value, the user will help you.

--

--

David Barral
Trabe
Editor for

Co-founder @Trabe. Developer drowning in a sea of pointless code.