Functional BytesFunctional Bytes

Tracking the Previous Page using React Context


Context Code

The context is used to store the previous path. This is done by watching the routing path (router.asPath for NextJS) and updating the context state when it changes. It is initialized to undefined and the current path is stored in a mutable ref so that it can be stored when the path changes.

File: src/contexts/RoutingContext.tsx

import { useRouter } from 'next/router';
import React, { ReactNode, useEffect, useRef, useState } from 'react';

export type RoutingContextState = {
  previousPath?: string;
};

export const DEFAULT_ROUTING_CONTEXT_VALUE: RoutingContextState = {
  previousPath: undefined,
};

export const RoutingContext = React.createContext(
  DEFAULT_ROUTING_CONTEXT_VALUE,
);

export type RoutingContextWrapperProps = {
  children: ReactNode;
};

export const RoutingContextWrapper = ({
  children,
}: RoutingContextWrapperProps) => {
  const router = useRouter();

  const [previousPath, setPreviousPath] = useState<string>();
  const currentPath = useRef<string>();

  useEffect(() => {
    setPreviousPath(currentPath.current);
    currentPath.current = router.asPath;
  }, [router.asPath]);

  return (
    <RoutingContext.Provider
      value={{
        previousPath,
      }}
    >
      {children}
    </RoutingContext.Provider>
  );
};

export default RoutingContext;

Usage

First wrap your app/page with the context. In NextJS this is done in pages/_app.tsx:

...

function AppName<P>({ Component, pageProps }: AppNameProps<P>) {
  return (
    <RoutingContextWrapper>
      <Head>
        <title>{APP_NAME}</title>
      </Head>
      <Component {...pageProps} />
    </RoutingContextWrapper>
  );
}

...

Then, where ever the previous path is needed, it can be retreived from the context:

const { previousPath } = useContext(RoutingContext);