Overview
The useLocation hook provides a simple interface to access the device’s GPS coordinates using the browser’s Geolocation API. It includes automatic initial location detection, comprehensive error handling, and manual refresh capability.
Usage
import { useLocation } from '@/hooks/useLocation' ;
const { coords , error , loading , refresh } = useLocation ();
Return Values
Geographic coordinates object, or null if not yet available Show Coordinates Properties
Latitude coordinate (-90 to 90)
Longitude coordinate (-180 to 180)
User-friendly error message in Spanish, or null if no error
true while fetching location, false when complete or failed
Function to manually trigger location refresh. Signature: () => void
Example
Basic Usage
With Manual Refresh
Conditional Rendering
import { useLocation } from '@/hooks/useLocation' ;
import { getCurrentWeather } from '@/lib/api/weather' ;
export default function WeatherApp () {
const { coords , error , loading , refresh } = useLocation ();
const [ weather , setWeather ] = useState ( null );
useEffect (() => {
if ( coords ) {
getCurrentWeather ( coords . lat , coords . lon )
. then ( setWeather );
}
}, [ coords ]);
if ( loading ) return < div > Detecting location ...</ div > ;
if ( error ) return < div > Error : { error } </ div > ;
if ( ! coords ) return < div > Location unavailable </ div > ;
return (
< div >
< p > Lat : { coords . lat }, Lon : { coords . lon }</ p >
{ weather && < p > Temp : { weather . main . temp }° C </ p >}
</ div >
);
}
Error Handling
The hook provides user-friendly error messages in Spanish based on the Geolocation API error codes:
Error Code Message (Spanish) Meaning 1 ”Permiso denegado. Activa la ubicación en los ajustes.” User denied permission 2 ”Ubicación no disponible. Revisa tu señal o GPS.” Position unavailable 3 ”Tiempo de espera agotado. Reintenta.” Timeout exceeded Unknown ”Error desconocido” Other errors
Error State Example
const { error } = useLocation ();
if ( error ) {
// Example errors:
// "Permiso denegado. Activa la ubicación en los ajustes."
// "Ubicación no disponible. Revisa tu señal o GPS."
// "Tiempo de espera agotado. Reintenta."
console . error ( 'Geolocation error:' , error );
}
Configuration
The hook uses the following Geolocation API options:
Requests the most accurate position available. Critical for mobile devices.
Maximum time (in milliseconds) to wait for position. Set to 15 seconds to accommodate slower mobile GPS connections.
Maximum age of cached position. Set to 0 to force fresh location data.
Customizing Options
If you need different configuration, modify the hook source:
const options : PositionOptions = {
enableHighAccuracy: true , // Best accuracy
timeout: 15000 , // 15 seconds
maximumAge: 0 // No cache
};
Behavior
Automatic Initial Detection
The hook automatically attempts to get the user’s location on mount:
useEffect (() => {
getLocation ( false ); // Automatic, non-manual attempt
}, [ getLocation ]);
Manual Refresh
Calling refresh() triggers a new location request:
const { refresh } = useLocation ();
// User clicks GPS button
refresh (); // Manually triggers location fetch
The difference between automatic and manual:
Automatic (isManual=false): Clears previous errors immediately
Manual (isManual=true): Preserves error state until new position is received, providing better user feedback
Browser Compatibility
The hook checks for Geolocation API support:
if ( ! navigator . geolocation ) {
setError ( "Tu navegador no soporta geolocalización" );
setLoading ( false );
return ;
}
Supported Browsers
Chrome/Edge 5+
Firefox 3.5+
Safari 5+
Opera 10.6+
iOS Safari 3.2+
Android Browser 2.1+
Security Considerations
HTTPS Requirement
Geolocation API requires HTTPS in production:
✅ https://yourdomain.com
✅ http://localhost (development only)
❌ http://yourdomain.com (will fail)
Permission Prompts
Browsers will prompt users for location permission:
First call triggers browser permission dialog
User choice is remembered for the domain
Denied permission results in error code 1
Privacy Best Practices
// Good: Explain why you need location
< div >
< p > We need your location to show local weather </ p >
< button onClick = { refresh } > Enable Location </ button >
</ div >
// Bad: Request without context
< button onClick = { refresh } > Click Here </ button >
Avoiding Unnecessary Refreshes
const { coords , refresh } = useLocation ();
// Good: Only refresh when user explicitly requests
< button onClick = { refresh } > Update Location </ button >
// Bad: Refreshing on every render
useEffect (() => {
refresh (); // Infinite loop!
}, [ coords ]);
Caching Coordinates
const { coords } = useLocation ();
const [ savedCoords , setSavedCoords ] = useState ( null );
useEffect (() => {
if ( coords ) {
// Save to localStorage for offline use
localStorage . setItem ( 'lastCoords' , JSON . stringify ( coords ));
setSavedCoords ( coords );
}
}, [ coords ]);
Troubleshooting
Location Not Detected
Check browser support : Ensure navigator.geolocation exists
Verify HTTPS : Geolocation requires secure context
Check permissions : User may have denied access
Mobile GPS : Ensure location services are enabled in device settings
Timeout Errors
// Increase timeout for slow connections
const options : PositionOptions = {
enableHighAccuracy: true ,
timeout: 30000 , // 30 seconds instead of 15
maximumAge: 0
};
Accuracy Issues
Desktop : Typically uses IP-based location (less accurate)
Mobile : Uses GPS when enableHighAccuracy: true
Indoors : GPS signal may be weak or unavailable
Integration Examples
With Weather API
import { useLocation } from '@/hooks/useLocation' ;
import { getCurrentWeather } from '@/lib/api/weather' ;
const { coords } = useLocation ();
const [ weather , setWeather ] = useState ( null );
useEffect (() => {
if ( coords ) {
getCurrentWeather ( coords . lat , coords . lon )
. then ( data => setWeather ( data ));
}
}, [ coords ]);
With Maps
import { useLocation } from '@/hooks/useLocation' ;
import { MapContainer , Marker } from 'react-leaflet' ;
const { coords } = useLocation ();
return coords ? (
< MapContainer center = { [coords.lat, coords.lon]} zoom={13}>
<Marker position={[coords.lat, coords.lon]} />
</MapContainer>
) : null ;