useRouter

If you use React Router you might have noticed they recently added a number of useful hooks, specifically useParams, useLocation, useHistory, and use useRouteMatch. But let's see if we can make it even simpler by wrapping them up into a single useRouter hook that exposes just the data and methods we need. In this recipe we show how easy it is to compose multiple hooks and combine their returned state into a single object. It makes a lot of sense for libraries like React Router to offer a selection of low-level hooks, as using only the hook you need can minimize unnecessary re-renders. That said, sometimes you want a simpler developer experience and custom hooks make that easy.

Usage

useRouter.ts
import { useState, useEffect } from 'react';

interface RouterObject {
  pathname: string;
  search: string;
  hash: string;
  state: any;
}

const useRouter = (): RouterObject => {
  const [location, setLocation] = useState<RouterObject>({
    pathname: window.location.pathname,
    search: window.location.search,
    hash: window.location.hash,
    state: null,
  });

  useEffect(() => {
    const handleLocationChange = () => {
      setLocation({
        pathname: window.location.pathname,
        search: window.location.search,
        hash: window.location.hash,
        state: history.state,
      });
    };
    window.addEventListener('popstate', handleLocationChange);
    return () => window.removeEventListener('popstate', handleLocationChange);
  }, []);

  return location;
};

export default useRouter;

This useRouter hook uses the useState and useEffect hooks from React to manage the router information. It creates a location state variable that contains the current pathname, search query string, hash, and state. It also listens for changes to the URL using the popstate event, and updates the location state variable when the URL changes.

To use the useRouter hook in your React components, simply import it and call it to get the router information:

import useRouter from './useRouter';

const MyComponent = () => {
  const router = useRouter();

  return (
    <div>
      <p>Current pathname: {router.pathname}</p>
      <p>Search query string: {router.search}</p>
      <p>Hash: {router.hash}</p>
    </div>
  );
};

In this example, we import the useRouter hook and call it to get the router information. We then use that information to display the current pathname, search query string, and hash.

Last updated