useHooks.iov4.1.2
DocsBlogGitHub
Hooks
No hooks found in any category.

useGeolocation

sensors

Installation

npx usehooks-cli@latest add use-geolocation

Description

A React hook for accessing the user's geolocation with support for both one-time position requests and continuous position watching, including comprehensive error handling and configuration options.

Parameters

NameTypeDefaultDescription
options?GeolocationOptions{ enableHighAccuracy: false, timeout: Infinity, maximumAge: 0 }Geolocation API options for accuracy, timeout, and cache settings

Return Type

GeolocationState & { getCurrentPosition: () => void, startWatching: () => void, stopWatching: () => void }
PropertyTypeDescription
loadingbooleanTrue when requesting location data
latitudenumber | nullCurrent latitude coordinate
longitudenumber | nullCurrent longitude coordinate
accuracynumber | nullAccuracy of the position in meters
altitudenumber | nullAltitude above sea level in meters
altitudeAccuracynumber | nullAccuracy of altitude measurement in meters
headingnumber | nullDirection of travel in degrees (0-360)
speednumber | nullCurrent speed in meters per second
timestampnumber | nullTimestamp when position was acquired
errorGeolocationPositionError | nullError object if geolocation failed
getCurrentPosition() => voidGet current position once
startWatching() => voidStart continuously watching position changes
stopWatching() => voidStop watching position changes

Examples

Current Location Display

Getting and displaying the user's current location

1const { 2 latitude, 3 longitude, 4 accuracy, 5 loading, 6 error, 7 getCurrentPosition 8} = useGeolocation({ 9 enableHighAccuracy: true, 10 timeout: 10000 11}); 12 13return ( 14 <div> 15 <button onClick={getCurrentPosition} disabled={loading}> 16 {loading ? 'Getting Location...' : 'Get My Location'} 17 </button> 18 19 {error && ( 20 <div className="error"> 21 Error: {error.message} 22 </div> 23 )} 24 25 {latitude && longitude && ( 26 <div className="location-info"> 27 <p>Latitude: {latitude.toFixed(6)}</p> 28 <p>Longitude: {longitude.toFixed(6)}</p> 29 <p>Accuracy: ±{accuracy?.toFixed(0)}m</p> 30 </div> 31 )} 32 </div> 33);

Live Location Tracking

Continuously tracking user's position for navigation

1const { 2 latitude, 3 longitude, 4 speed, 5 heading, 6 loading, 7 error, 8 startWatching, 9 stopWatching 10} = useGeolocation({ 11 enableHighAccuracy: true, 12 timeout: 5000, 13 maximumAge: 1000 14}); 15 16const [isTracking, setIsTracking] = useState(false); 17 18const toggleTracking = () => { 19 if (isTracking) { 20 stopWatching(); 21 setIsTracking(false); 22 } else { 23 startWatching(); 24 setIsTracking(true); 25 } 26}; 27 28return ( 29 <div> 30 <button onClick={toggleTracking}> 31 {isTracking ? 'Stop Tracking' : 'Start Tracking'} 32 </button> 33 34 {loading && <div>📍 Getting location...</div>} 35 36 {latitude && longitude && ( 37 <div className="tracking-info"> 38 <h3>Current Position</h3> 39 <p>📍 {latitude.toFixed(6)}, {longitude.toFixed(6)}</p> 40 {speed && <p>🏃 Speed: {(speed * 3.6).toFixed(1)} km/h</p>} 41 {heading && <p>🧭 Heading: {heading.toFixed(0)}°</p>} 42 </div> 43 )} 44 </div> 45);

Distance Calculator

Calculating distance between user and a target location

1const { latitude, longitude, error, getCurrentPosition } = useGeolocation(); 2const [targetLocation] = useState({ lat: 40.7128, lng: -74.0060 }); // NYC 3const [distance, setDistance] = useState(null); 4 5// Haversine formula for distance calculation 6const calculateDistance = (lat1, lon1, lat2, lon2) => { 7 const R = 6371; // Earth's radius in km 8 const dLat = (lat2 - lat1) * Math.PI / 180; 9 const dLon = (lon2 - lon1) * Math.PI / 180; 10 const a = Math.sin(dLat/2) * Math.sin(dLat/2) + 11 Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * 12 Math.sin(dLon/2) * Math.sin(dLon/2); 13 const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 14 return R * c; 15}; 16 17useEffect(() => { 18 if (latitude && longitude) { 19 const dist = calculateDistance( 20 latitude, longitude, 21 targetLocation.lat, targetLocation.lng 22 ); 23 setDistance(dist); 24 } 25}, [latitude, longitude, targetLocation]); 26 27return ( 28 <div> 29 <button onClick={getCurrentPosition}> 30 Calculate Distance to NYC 31 </button> 32 33 {error && <div>Error: {error.message}</div>} 34 35 {distance && ( 36 <div> 37 <p>Distance to New York City:</p> 38 <p><strong>{distance.toFixed(2)} km</strong></p> 39 </div> 40 )} 41 </div> 42);

Dependencies

react

Notes

  • Requires user permission to access location data
  • Works only in secure contexts (HTTPS) in most browsers
  • Automatically cleans up watch positions on component unmount
  • Provides comprehensive position data including altitude, speed, and heading
  • Supports both one-time position requests and continuous watching
  • Handles browser compatibility and provides meaningful error messages

Implementation

1'use client'; 2 3import { useState, useEffect, useCallback, useRef } from "react"; 4 5export interface GeolocationState { 6 loading: boolean; 7 accuracy: number | null; 8 altitude: number | null; 9 altitudeAccuracy: number | null; 10 heading: number | null; 11 latitude: number | null; 12 longitude: number | null; 13 speed: number | null; 14 timestamp: number | null; 15 error: GeolocationPositionError | null; 16} 17 18export interface GeolocationOptions { 19 enableHighAccuracy?: boolean; 20 timeout?: number; 21 maximumAge?: number; 22} 23 24const defaultOptions: GeolocationOptions = { 25 enableHighAccuracy: false, 26 timeout: Infinity, 27 maximumAge: 0, 28}; 29 30export function useGeolocation(options: GeolocationOptions = defaultOptions) { 31 const [state, setState] = useState<GeolocationState>({ 32 loading: true, 33 accuracy: null, 34 altitude: null, 35 altitudeAccuracy: null, 36 heading: null, 37 latitude: null, 38 longitude: null, 39 speed: null, 40 timestamp: null, 41 error: null, 42 }); 43 44 const watchIdRef = useRef<number | null>(null); 45 const optionsRef = useRef(options); 46 47 // Update options ref when options change 48 useEffect(() => { 49 optionsRef.current = options; 50 }, [options]); 51 52 const onSuccess = useCallback((position: GeolocationPosition) => { 53 setState({ 54 loading: false, 55 accuracy: position.coords.accuracy, 56 altitude: position.coords.altitude, 57 altitudeAccuracy: position.coords.altitudeAccuracy, 58 heading: position.coords.heading, 59 latitude: position.coords.latitude, 60 longitude: position.coords.longitude, 61 speed: position.coords.speed, 62 timestamp: position.timestamp, 63 error: null, 64 }); 65 }, []); 66 67 const onError = useCallback((error: GeolocationPositionError) => { 68 setState((prev) => ({ 69 ...prev, 70 loading: false, 71 error, 72 })); 73 }, []); 74 75 const getCurrentPosition = useCallback(() => { 76 if (!navigator.geolocation) { 77 onError({ 78 code: 2, 79 message: "Geolocation is not supported by this browser.", 80 } as GeolocationPositionError); 81 return; 82 } 83 84 setState((prev) => ({ ...prev, loading: true, error: null })); 85 navigator.geolocation.getCurrentPosition( 86 onSuccess, 87 onError, 88 optionsRef.current 89 ); 90 }, [onSuccess, onError]); 91 92 const startWatching = useCallback(() => { 93 if (!navigator.geolocation) { 94 onError({ 95 code: 2, 96 message: "Geolocation is not supported by this browser.", 97 } as GeolocationPositionError); 98 return; 99 } 100 101 if (watchIdRef.current !== null) { 102 navigator.geolocation.clearWatch(watchIdRef.current); 103 } 104 105 setState((prev) => ({ ...prev, loading: true, error: null })); 106 watchIdRef.current = navigator.geolocation.watchPosition( 107 onSuccess, 108 onError, 109 optionsRef.current 110 ); 111 }, [onSuccess, onError]); 112 113 const stopWatching = useCallback(() => { 114 if (watchIdRef.current !== null) { 115 navigator.geolocation.clearWatch(watchIdRef.current); 116 watchIdRef.current = null; 117 } 118 }, []); 119 120 // Cleanup on unmount 121 useEffect(() => { 122 return () => { 123 if (watchIdRef.current !== null) { 124 navigator.geolocation.clearWatch(watchIdRef.current); 125 } 126 }; 127 }, []); 128 129 return { 130 ...state, 131 getCurrentPosition, 132 startWatching, 133 stopWatching, 134 }; 135} 136