Hone logo
Hone
Problems

React useLocation Hook Challenge

This challenge asks you to create a custom React hook, useLocation, that mirrors the functionality of the useLocation hook found in popular routing libraries like react-router-dom. The goal is to provide a way for your React components to access and react to changes in the current URL's location object. This is fundamental for building single-page applications (SPAs) that navigate without full page reloads.

Problem Description

Your task is to implement a custom React hook named useLocation in TypeScript. This hook should return the current Location object, which includes properties like pathname, search, and hash. Crucially, the hook must also re-render the component calling it whenever the browser's location changes.

Key Requirements:

  • Hook Signature: The hook should be a function named useLocation and should return the browser's Location object.
  • State Management: The hook must maintain the current location state.
  • Event Listener: It needs to listen for changes in the browser's location. The popstate event is the primary event for tracking history navigation (back/forward buttons), and hashchange is for fragment identifier changes.
  • Re-rendering on Change: When a location change occurs, components using useLocation should automatically re-render to reflect the updated URL.
  • Cleanup: Ensure that the event listeners are properly removed when the component unmounts to prevent memory leaks.
  • TypeScript: The solution must be written in TypeScript, leveraging its type safety features.

Expected Behavior:

A component calling useLocation should receive the latest Location object. If the user navigates to a different URL (e.g., by clicking a link that doesn't cause a full page reload, or using browser back/forward buttons), the component should update with the new location details.

Edge Cases:

  • Initial Load: The hook should correctly capture the initial location when the component mounts.
  • SPA Navigation: Consider how your hook would interact with a hypothetical SPA routing mechanism that manipulates the browser history API (pushState, replaceState) without triggering a full page reload.

Examples

Example 1:

// Assume this is within a React component
import React from 'react';
import { useLocation } from './useLocation'; // Your custom hook

function LocationDisplay() {
  const location = useLocation();

  return (
    <div>
      <p>Pathname: {location.pathname}</p>
      <p>Search: {location.search}</p>
      <p>Hash: {location.hash}</p>
    </div>
  );
}

// Usage in your App:
// <LocationDisplay />

Input (Browser URL): http://localhost:3000/about?source=docs#section1

Output (Rendered in LocationDisplay):

Pathname: /about
Search: ?source=docs
Hash: #section1

Explanation: The useLocation hook reads the current browser URL and provides its components.

Example 2:

Scenario: The user is on http://localhost:3000/home and clicks a link that changes the URL to http://localhost:3000/settings?theme=dark.

Input (Browser URL change): From http://localhost:3000/home to http://localhost:3000/settings?theme=dark.

Output (Rendered in LocationDisplay after navigation):

Pathname: /settings
Search: ?theme=dark
Hash:

Explanation: The useLocation hook detects the URL change (likely via popstate or a custom event if you're simulating SPA routing) and updates its internal state. The LocationDisplay component, subscribed to these changes, re-renders with the new location data.

Constraints

  • The hook must use browser native APIs for accessing location information.
  • The hook should be idempotent; calling it multiple times within the same component render should return the same Location object for that render.
  • Performance is important: avoid unnecessary re-renders or expensive computations within the hook.

Notes

  • You'll need to access the global window.location object.
  • Consider using useState to store the location object and useEffect for managing side effects like event listeners.
  • The popstate event fires when the active history entry changes (e.g., due to the user navigating history).
  • For more complex SPA routing that uses history.pushState or history.replaceState, you might need to augment your solution to listen for custom events or monkey-patch history methods if you were building a full routing library. For this challenge, focusing on popstate and hashchange is sufficient to demonstrate the core concept.
  • Success means creating a hook that correctly reflects the browser's current URL and triggers component updates when that URL changes.
Loading editor...
typescript