Lesson 12. Custom hooks to use the browser’s APIs 5. Get the user’s geolocation
To conclude this lesson, let’s see another example of the browser’s API, which you can access very elegantly via a custom hook: the geolocation API. As its name suggests, the idea is to get the user’s location, meaning the latitude and longitude of their position. Of course, this API can be used only on devices supporting it (mobile devices, modern browsers) and only if the user agreed to be geolocated.
You can access this API using the navigator.geolocation object, more precisely
its method getCurrentPosition. It accepts two callback parameters: one
executed when the browser successfully returns the current position, the other
when an error occurred, meaning the device does not support geolocation or the
user didn’t authorize the page to get it.
navigator.geolocation.getCurrentPosition((res) => console.log(res.coords.latitude, res.coords.longitude),(err) => console.log('Impossible to get current position'))
To return the user’s current position via a custom hook, we will apply the same pattern we used in the previous two examples:
- Keep a local state with the position.
- Call the geolocation API in a
useEffectto update the state. - Return its values.
We’ll introduce a small difference, though: since we want to handle the error
case, we will also return a status attribute indicating if we are waiting for
the position ('pending'), if we fetched it successfully ('success'), or if
an error occurred ('error').
const useGeolocation = () => {const [status, setStatus] = useState('pending')const [latitude, setLatitude] = useState(undefined)const [longitude, setLongitude] = useState(undefined)useEffect(() => {let active = truenavigator.geolocation.getCurrentPosition((res) => {if (active) {setStatus('success')setLatitude(res.coords.latitude)setLongitude(res.coords.longitude)}},(err) => {if (active) {console.log(err)setStatus('error')}})return () => (active = false)}, [])return { status, latitude, longitude }}
In the components using this hook, we can then use the returned status
attribute to decide what to display:
export const Comp = () => {const { status, latitude, longitude } = useGeolocation()switch (status) {case 'pending':return <p>Waiting for geolocation…</p>case 'success':return (<p>Your location: ({latitude}, {longitude})</p>)case 'error':return <p>Have you authorized me to access your geolocation?</p>}}
Here is the complete example:
Result
With these three custom hooks examples to use the browser’s APIs, you probably notice that the recipe is very similar. With this in mind, you are now able to write many custom hooks. It doesn’t mean that they will solve every problem, but they are an additional tool you can use to make your code cleaner, especially when you want to access features provided by the browser.