Transforming Coordinates into Human-Readable Addresses with useReverseGeocoding
The Back Story about your Javascript Metaphor
As a software freestyle engineer, you know that location-based features are becoming more and more common in web and mobile applications. However, sometimes it's not enough to simply display a set of coordinates to the user. To provide a better user experience, it's important to translate those coordinates into a human-readable address that users can easily understand. This is where reverse geocoding comes in.
The javascript Story!
Requirements
In order to achieve the functionality I needed, I started by importing two useful tools: useState
and useEffect
from the React library, and the react-geocode
package. I also imported a utility function called toObjectCoordinate
which converts a comma-separated string into an object with lat
and lng
keys. With these tools, I was able to create a custom hook called useReverseGeocoding
, which accepts two optional parameters for latitude and longitude and returns an address string and two state setters for latitude and longitude.
The Utils
1export default function toObjectCoordinate(latLong) { 2 const index = latLong.split(',') 3 return { 4 lat: index[0], 5 lng: index[1] 6 } 7}
The above function takes a string parameter latLong
, which is a comma-separated string of latitude and longitude values. The function splits the string using the comma as a separator and returns an object with two properties - lat
and lng
.
The Hook
1import { useState, useEffect } from "react"; 2import Geocode from "react-geocode"; 3import { maps } from '../constants/maps'; 4 5Geocode.setApiKey(maps.key); 6 7const useReverseGeocoding = (lat = null, lng = null) => { 8 const [address, setAddress] = useState(""); 9 const [latitude, setLatitide] = useState(lat); 10 const [longitude, setLongitude] = useState(lng); 11 12 useEffect(() => { 13 if (latitude !== null || longitude !== null) { 14 Geocode.fromLatLng(latitude, longitude).then( 15 (response) => { 16 const address = response.results[0].formatted_address; 17 setAddress(address); 18 }, 19 (error) => { 20 console.error(error); 21 } 22 ); 23 } 24 }, [latitude, longitude]); 25 26 return { address, setLatitide, setLongitude }; 27}; 28 29export default useReverseGeocoding;
The code then defines a custom hook called useReverseGeocoding
. The hook takes two parameters - lat
and lng
- which are set to null by default. Inside the hook, three state variables are defined using the useState
hook - address
, latitude
, and longitude
. The hook also defines an effect that runs whenever latitude or longitude changes. The effect calls the fromLatLng
method of the Geocode
object to get the address from the geographic coordinates. If the call is successful, the address is stored in the address state variable. If there is an error, it is logged to the console.
The hook returns an object with three properties - address
, setLatitude
, and setLongitude
. The address
property contains the human-readable address obtained from the geographic coordinates. The setLatitude
and setLongitude
functions can be used to set the latitude
and longitude
state variables, respectively.
The Component
1import { Form, Formik, useFormikContext } from 'formik' 2import ValidationMessage from '../../../forms/ValidationMessage' 3import useReverseGeocoding from '../../../hooks/useReverseGeocoding' 4import toObjectCoordinate from '../../../Utils/toObjectCoordinate' 5import React, { useState, useEffect, useCallback } from 'react' 6import { Helmet } from 'react-helmet' 7import { NewCustomer } from '../../../forms/states/NewCustomer' 8import { customerValidation } from '../../../forms/validations/customerValidation' 9 10const AddressReceiver = ({ address }) => { 11 const { setFieldValue } = useFormikContext() 12 13 useEffect(() => { 14 setFieldValue('customerAddress', address) 15 }, [address]) 16 return null 17} 18 19 20function FormCustomer() { 21 const { address, setLatitide, setLongitude } = useReverseGeocoding() 22 return ( 23 <> 24 <Helmet> 25 <title>Add New Customer</title> 26 </Helmet> 27 <section className='w-9/12 my-3 mx-auto'> 28 <Formik 29 initialValues={NewCustomer} 30 validationSchema={customerValidation} 31 enableReinitialize={true} 32 onSubmit={handleSubmit} 33 > 34 {({ values, errors, touched, handleChange, setFieldValue }) => ( 35 <Form autoComplete='off'> 36 {/* All form field... */} 37 <div className="form-control w-full"> 38 <label className="label"> 39 <span className="label-text">Coordinate <sup className="text-error">*</sup></span> 40 </label> 41 <input type="text" name='customerCoordinate' value={values.customerCoordinate} onChange={(e) => { 42 const value = e.target.value 43 const { lat, lng } = toObjectCoordinate(value) 44 setLatitide(lat) 45 setLongitude(lng) 46 setFieldValue('customerCoordinate', value) 47 }} placeholder="Type here" className="input input-md input-bordered w-full" /> 48 <ValidationMessage name='customerCoordinate' errors={errors} touched={touched} /> 49 </div> 50 <div className="form-control w-full col-span-3"> 51 <label className="label"> 52 <span className="label-text">Address <sup className="text-error">*</sup></span> 53 </label> 54 <input type="text" name='customerAddress' value={values.customerAddress} onChange={handleChange} placeholder="Type here" className="input input-md input-bordered w-full" /> 55 <ValidationMessage name='customerAddress' errors={errors} touched={touched} /> 56 </div> 57 <AddressReceiver address={address} /> 58 </Form> 59 )} 60 </Formik> 61 </section> 62 </> 63 ) 64}
The FormCustomer
component is a form that allows the user to input customer details, including their coordinate and address. The component utilizes the useReverseGeocoding
hook to simplify the process of inputting the customer's address. When the user inputs the customer's coordinate, the toObjectCoordinate
function is used to extract the latitude and longitude values and pass them to the setLatitude
and setLongitude
functions. This triggers the useEffect
hook in the useReverseGeocoding
function, which performs the reverse geocoding
and updates the address variable. The AddressReceiver
component is used to update the customerAddress
field in the form with the retrieved address.
The Result
The Conclusion
Reverse geocoding is an important feature for location-based applications that allows coordinates to be translated into human-readable addresses. The useReverseGeocoding hook and toObjectCoordinate utility function provided in the code snippet make it easy to implement reverse geocoding in a React application. By using these tools, developers can provide a better user experience by displaying easily understandable addresses to their users.
A Javascript demo/repos link
None