useGeolocation
A custom React hook for getting the user's geolocation from the Geolocation API (opens in a new tab).
Props
options
(optional): an object with the following properties:enableHighAccuracy
(optional): a boolean that indicates whether to provide a more accurate position.maximumAge
(optional): a number that indicates the maximum age of the cached position in milliseconds.timeout
(optional): a number that indicates the maximum length of time in milliseconds to wait for a position.
callback
(optional): a function that will be called when the position changes. The function will be passed the current coordinates object. -isEnabled
(optional): a boolean that indicates whether the hook should start watching for position changes.
Returns
An object with the following properties:
-
accuracy
: a number that indicates the accuracy of the position in meters. -
altitude
: a number that indicates the altitude of the position in meters above the mean sea level -
altitudeAccuracy
: a number that indicates the accuracy of the altitude in meters. -
heading
: a number that indicates the direction of the device in degrees. -
latitude
: a number that indicates the latitude of the position. -
longitude
: a number that indicates the longitude of the position. -
speed
: a number that indicates the speed of the device in meters per second. -
timestamp
: a number that indicates the timestamp of the position. -
error
: an object that indicates an error if one occurred while trying to get the position.
The Hook
import { useState, useEffect, useCallback } from 'react'
type PositionError = GeolocationPositionError
interface GeolocationOptions {
enableHighAccuracy?: boolean
maximumAge?: number
timeout?: number
}
interface Coordinates {
accuracy: number | null
altitude: number | null
altitudeAccuracy: number | null
heading: number | null
latitude: number | null
longitude: number | null
speed: number | null
timestamp: number | null
error: PositionError | null
}
export const useGeolocation = (
options: GeolocationOptions = {},
callback?: (coordinates: Coordinates) => void,
isEnabled = true
) => {
const [coordinates, setCoordinates] = useState<Coordinates>({
accuracy: null,
altitude: null,
altitudeAccuracy: null,
heading: null,
latitude: null,
longitude: null,
speed: null,
timestamp: null,
error: null
})
const updateCoordinates = useCallback(
({ coords, timestamp }: GeolocationPosition) => {
const {
accuracy,
altitude,
altitudeAccuracy,
heading,
latitude,
longitude,
speed
} = coords
setCoordinates({
accuracy,
altitude,
altitudeAccuracy,
heading,
latitude,
longitude,
speed,
timestamp,
error: null
})
if (typeof callback === 'function') {
callback({
accuracy,
altitude,
altitudeAccuracy,
heading,
latitude,
longitude,
speed,
timestamp,
error: null
})
}
},
[callback]
)
const setError = useCallback((error: PositionError) => {
setCoordinates({
accuracy: null,
altitude: null,
altitudeAccuracy: null,
heading: null,
latitude: null,
longitude: null,
speed: null,
timestamp: null,
error
})
}, [])
useEffect(() => {
let watchId: number
if (isEnabled && navigator.geolocation) {
navigator.geolocation.getCurrentPosition(updateCoordinates, setError)
watchId = navigator.geolocation.watchPosition(
updateCoordinates,
setError,
options
)
}
return () => {
if (watchId) {
navigator.geolocation.clearWatch(watchId)
}
}
}, [isEnabled, callback, options, setError, updateCoordinates])
return coordinates
}
Usage
import React from 'react'
import { useGeolocation } from './useGeolocation'
export const UseGeolocationDemo = () => {
const coordinates = useGeolocation()
return !coordinates.error ? (
<ul>
<li>Latitude: {coordinates.latitude}</li>
<li>Longitude: {coordinates.longitude}</li>
<li>Location accuracy: {coordinates.accuracy}</li>
<li>Altitude: {coordinates.altitude}</li>
<li>Altitude accuracy: {coordinates.altitudeAccuracy}</li>
<li>Heading: {coordinates.heading}</li>
<li>Speed: {coordinates.speed}</li>
<li>Timestamp: {coordinates.timestamp}</li>
</ul>
) : (
<p>No geolocation, sorry.</p>
)
}
Using PositionOptions
You can use the options parameter to pass PositionOptions to the watchPosition method of the Geolocation API. The PositionOptions object can be used to fine-tune the response from the watchPosition method.
const options = {
enableHighAccuracy: true,
maximumAge: 15000,
timeout: 12000
}
const coordinates = useGeolocation(options)
In this example, the options object is passed to the useGeolocation hook. This will configure the watchPosition method to use high accuracy, return a cached position that is no older than 15 seconds, and wait for a maximum of 12 seconds to get a position.
Using a callback function
You can also pass a callback function as a second parameter to useGeolocation. The callback function will be called every time the position changes and will be passed the current coordinates object.
import { useGeolocation } from './useGeolocation'
function Component() {
const options = {
enableHighAccuracy: true,
maximumAge: 15000,
timeout: 12000
}
const handlePositionChange = (coordinates) => {
console.log(coordinates)
}
const coordinates = useGeolocation(options, handlePositionChange)
return <div>Latitude: {coordinates.latitude}</div>
}
In this example, the handlePositionChange function will be called every time the user's position changes, and the current coordinates object will be passed to it as an argument. You can use this function to perform some action or update some state in your component every time the position changes.