Hone logo
Hone
Problems

React Custom Hook: useGeolocation

This challenge involves creating a custom React hook, useGeolocation, that gracefully handles fetching and managing the user's geographical location. This is a fundamental building block for many location-aware applications, such as mapping services, location-based recommendations, and weather apps.

Problem Description

Your task is to build a reusable React hook called useGeolocation that encapsulates the logic for accessing the browser's Geolocation API. The hook should provide the current geographical coordinates (latitude and longitude), as well as the status of the geolocation request.

Key Requirements:

  1. State Management: The hook should maintain state for:

    • latitude: The user's latitude (number | null).
    • longitude: The user's longitude (number | null).
    • error: Any error message encountered during the geolocation request (string | null).
    • isLoading: A boolean indicating whether the geolocation request is currently in progress.
  2. Geolocation API Integration:

    • When the hook is first used, it should attempt to get the user's current position using navigator.geolocation.getCurrentPosition().
    • Handle both successful retrieval of position and potential errors.
  3. Error Handling:

    • If navigator.geolocation.getCurrentPosition() fails, the error state should be updated with a descriptive message.
    • Consider common Geolocation API errors (e.g., permission denied, position unavailable).
  4. Loading State:

    • The isLoading state should be set to true when the geolocation request is initiated and false once the request is completed (either successfully or with an error).
  5. Re-fetching (Optional but Recommended):

    • Provide a way to re-trigger the geolocation request, perhaps through a returned function.
  6. Cleanup:

    • If the component using the hook unmounts before the geolocation request completes, ensure no state updates are attempted on an unmounted component.

Expected Behavior:

  • Initially, latitude, longitude, and error should be null, and isLoading should be true.
  • Upon successful retrieval, latitude and longitude should be updated with the actual coordinates, and isLoading should become false.
  • Upon encountering an error, error should be updated with the error message, and isLoading should become false.
  • If the browser does not support the Geolocation API, the hook should gracefully handle this, perhaps by setting an error message indicating lack of support.

Edge Cases to Consider:

  • Browser Support: The browser might not support the Geolocation API.
  • Permissions: The user might deny location permissions.
  • Location Unavailable: The device might be unable to determine the location.
  • Component Unmounting: The component using the hook might unmount before the asynchronous operation completes.

Examples

Example 1: Successful Geolocation

// Assuming the hook is used in a component like this:
const { latitude, longitude, error, isLoading } = useGeolocation();

// Initial state (before successful fetch):
// latitude: null
// longitude: null
// error: null
// isLoading: true

// After successful fetch (e.g., user grants permission and location is found):
// latitude: 34.0522
// longitude: -118.2437
// error: null
// isLoading: false

Example 2: Permission Denied Error

// Assuming the hook is used in a component like this:
const { latitude, longitude, error, isLoading } = useGeolocation();

// Initial state:
// latitude: null
// longitude: null
// error: null
// isLoading: true

// After user denies permission:
// latitude: null
// longitude: null
// error: "User denied Geolocation permission."
// isLoading: false

Example 3: Geolocation API Not Supported

// Assuming the hook is used in a component like this:
const { latitude, longitude, error, isLoading } = useGeolocation();

// If navigator.geolocation is undefined:
// latitude: null
// longitude: null
// error: "Geolocation API is not supported by this browser."
// isLoading: false

Constraints

  • The solution must be written in TypeScript.
  • The hook should be a functional component hook (using useState, useEffect, etc.).
  • Avoid using external libraries for geolocation. Rely solely on the browser's Geolocation API.
  • The hook should not block the UI thread during its operation.
  • The error messages provided should be informative.

Notes

  • You will need to use navigator.geolocation.getCurrentPosition(), which takes two optional callback functions: one for success and one for error.
  • The getCurrentPosition method can also take an optional options object, but for this challenge, default options are sufficient.
  • Consider how to handle the asynchronous nature of the Geolocation API within useEffect.
  • Remember to clean up any potential subscriptions or timers if you decide to implement a re-fetching mechanism that uses watchPosition (though getCurrentPosition is sufficient for the basic requirement).
Loading editor...
typescript