Osaretin
Osaretin
Tracking Previous Path with React Router v6 in Single-Page Applications
post image

Introduction:

In modern single-page applications (SPAs) built with React and React Router v6, tracking the previous path for analytics purposes, such as Google Analytics, is crucial for understanding user navigation patterns and optimizing the user experience. However, with the transition to React Router v6, traditional approaches using useHistory for accessing the navigation history are no longer applicable. In this article, we'll delve how to keep track of the previous path in React Router v6.

Understanding the Challenge:

  • React Router v6 deprecates the useHistory hook, making it challenging to access the navigation history and retrieve the previous path's URL.
  • Tracking the previous path is essential for analytics purposes, as it provides insights into how users navigate within the application and where they come from.
  • For example, Google Analytics relies on accurate previous path data to attribute traffic sources and measure user engagement effectively.

The Limitation of React Router v6:

  • React Router v6 does not provide built-in support for accessing the navigation history or retrieving the previous path's URL.
  • Direct access to window.history is not possible due to security concerns, limiting traditional approaches for tracking the previous path.

Solution: Custom Navigation Hooks: To overcome these challenges, we'll create custom navigation hooks that provide similar functionality to useHistory while also allowing us to track the previous path.

Implementing the useCustomNavigate Hook: The useCustomNavigate hook serves as a replacement for useHistory and provides enhanced navigation functionality. This hook utilizes useNavigate from React Router v6 to navigate between routes, updates the state value exposed by the router function and local storage with the previous path.

NB: we update localstorage so that files which are not react components can also have access to the prevPath value.

// Implementation of useCustomNavigate hook
// This hook provides enhanced navigation functionality and tracks the previous path
import { useNavigate, NavigateOptions } from 'react-router-dom';

const useCustomNavigate = () => {
  const navigate = useNavigate();

  const customNavigate = (to: string | number, options: NavigateOptions = {}) => {
    const currentPath = window.location.pathname;
    if (to === currentPath) {
      return;
    }
    localStorage.setItem('prevPath', window.location.href);

    const stateWithPrevPath = {
      ...options.state,
      prevPath: currentPath,
    };

    if (typeof to === 'number' && to === -1) {
      window.history.back();
    } else if (typeof to === 'string') {
      navigate(to, { ...options, state: stateWithPrevPath });
    }
  };

  return customNavigate;
};

export default useCustomNavigate;

Utilizing the Custom Hooks: We'll also create additional hooks, usePreviousPath and useUpdateLocalStorage, to retrieve the previous path from the router's state and update local storage with relevant data, respectively. These hooks seamlessly integrate with React Router v6 and provide efficient ways to track and manage the previous path within our application.

// Implementation of usePreviousPath and useUpdateLocalStorage hooks
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

export const usePreviousPath = () => {
  const location = useLocation();
  return location.state?.prevPath || '/';
};

export const useUpdateLocalStorage = (key: string, value: any) => {
  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [value, key]);
};

We can also extend the React router Link component with the custom navigation hook.


import { Link as ReactRouterLink } from 'react-router-dom';
import useCustomNavigate from 'PATH_TO_CUSTOME_HOOK';

interface CustomLinkProps {
  to: string;
  children: React.ReactNode;
  [key: string]: any;
}

const CustomLink: React.FC<CustomLinkProps> = ({ to, children, ...rest }) => {
  const customNavigate = useCustomNavigate();

  const handleNavigation = (event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
    // Prevent default link behavior if not an external link
    if (!to.startsWith('http')) {
      event.preventDefault();
      customNavigate(to);
    }
  };

  return (
    <ReactRouterLink to={to} onClick={handleNavigation} {...rest}>
      {children}
    </ReactRouterLink>
  );
};

export default CustomLink;

Conclusion:

With the implementation of custom navigation hooks, we've successfully addressed the challenges associated with React Router v6 navigation. These hooks provide a seamless way to navigate between routes while also enabling us to track and manage the previous path within our application. By leveraging these custom hooks, developers can enhance the navigation experience in their React applications and ensure smooth user interactions.

Closing Thoughts:

React Router v6 offers powerful navigation capabilities for React applications, and with the use of custom hooks and the state exposed by the navigation functions, developers can extend its functionality to meet their specific needs. By embracing custom navigation hooks, developers can overcome the limitations of React Router v6 and create more dynamic and interactive user experiences in their applications.


Osaretin Igbinobaro

Osaretin Igbinobaro

Software Engineer @ Apadmi


Osaretin


© 2024 osaretin.dev All rights reserved.