Transforming Coordinates into Human-Readable Addresses with useReverseGeocoding

darkterminal avatar
GitHub Account@darkterminal
LanguageJAVASCRIPT
Published At2023-04-04 01:02:22

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

Peek 2023-04-04 08-48

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

PayPal Link for Donation (Javascript Storyteller)

https://www.paypal.me/lazarusalhambra

Share This Story