Skip to content

Instantly share code, notes, and snippets.

@ali-sabry
Created April 8, 2023 17:21
Show Gist options
  • Save ali-sabry/5880a1702636349dc58d6e9becd4264b to your computer and use it in GitHub Desktop.
Save ali-sabry/5880a1702636349dc58d6e9becd4264b to your computer and use it in GitHub Desktop.
This custom hook will allows you to get the user's current location, which can be useful for location-based features in your app, without any third part library.
import { useState, useEffect } from 'react';
const useGeolocation = () => {
const [location, setLocation] = useState({
loaded: false,
coordinates: { latitude: '', longitude: '' },
});
const onSuccess = (location) => {
setLocation({
loaded: true,
coordinates: {
latitude: location.coords.latitude,
longitude: location.coords.longitude,
},
});
};
const onError = (error) => {
setLocation({
loaded: true,
error,
});
};
useEffect(() => {
if (!('geolocation' in navigator)) {
onError({
code: 0,
message: 'Geolocation not supported',
});
}
navigator.geolocation.getCurrentPosition(onSuccess, onError);
}, []);
return location;
};
//==== Usage
const App = () => {
const { loaded, coordinates, error } = useGeolocation();
const { latitude, longitude } = coordinates;
const [country, setCountry] = useState('');
useEffect(() => {
const url =
`https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${latitude}&longitude=${longitude}&localityLanguage=en`;
fetch(url)
.then(response => response.json())
.then(data => setCountry(data.countryName))
.catch(error => console.error(error));
}, [latitude, longitude]);
if (error) <div>Error: {error.message}</div>;
if (!loaded) <div>Loading...</div>;
return <div>Country: {country} </div> //=== Egypt
}
export default App;
@ECorreia45
Copy link

ECorreia45 commented Apr 16, 2023

Made some adjustments

  • the initial state does not contain error
  • no need for onError and onSuccess since they are not reused
  • if there is no geolocation in navigator the line where you getCurrentPosition will fail so i put it in the else
  • is common to use loading instead of loaded
  • the location.coords looks similar to coordinates so no need to break it down.
  • renamed location to state. You are definiting the state of the hook not "location" data
  • no need to wait for render to check if geolocation is supported and update state
const geolocationIsSupported = 'geolocation' in navigator;

const useGeolocation = () => {
  const [state, setState] = useState({
    loading: geolocationIsSupported,
    coordinates: { latitude: '', longitude: '' },
    error: geolocationIsSupported ? null : new Error('Geolocation not supported')
  });

  useEffect(() => {
    if (geolocationIsSupported) {
      navigator.geolocation.getCurrentPosition(
        (location) => {
          setState({
            loading: false,
            coordinates: location.coords,
          });
        },
        (error) => {
          setState({
            loading: false,
            error,
          });
        });
    }
  }, []);

  return state;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment