DEV Community

Frulow
Frulow

Posted on

Handling Routes In React.js | A Custom Approach

Hey there! If you've ever worked with React, you know how important routes are—they're what connect different pages or sections of your app. However, dealing with them can be a bit tricky.

So, I came up with a nifty way to handle route paths neatly, all in one file, and easily share them across your entire app.

Let's dive into the code:

export const AppRoutePaths = {
  home: '',
  auth: 'auth',
  project: {
    index: 'project',
    create: 'create',
    manage: {
      index: 'manage',
      byId: ({ id }: { id: string }) => `${id}`,
    },
  },
  // ... (other routes)
};

function createAppRouterFullPath(routePaths: Record<string, any>, parentPath = '') {
  let fullPath: Record<string, string> = {};

  for (const key in routePaths) {
    const value = routePaths[key as keyof typeof AppRoutePaths];
    const propKey = parentPath
      ? [parentPath, key]
          .filter((item) => !item.match(/^(?:false|null|undefined|0|NaN|''|""|`.*?`)$/i))
          .join('.')
          .replaceAll('/', '.')
      : key;

    if (typeof value === 'string') {
      fullPath[propKey] = parentPath ? `${parentPath}/${value}` : value;
    } else if (typeof value === 'function') {
      fullPath[propKey] = parentPath
        ? `${parentPath}/${value({ id: ':id' })}`
        : value({ id: ':id' });
    } else if (typeof value === 'object') {
      const nestedFullPath = createAppRouterFullPath(
        value,
        parentPath ? `${parentPath}/${key}` : key
      );
      fullPath = { ...fullPath, ...nestedFullPath };
    }
  }

  return fullPath;
}

export const AppRouterFullPath = createAppRouterFullPath(AppRoutePaths);

Enter fullscreen mode Exit fullscreen mode

Now, let's talk about the purpose of the createAppRouterFullPath function:

If you noticed, the routes inside AppRoutePaths are nested but not connected to their parent. This function helps link them together.

Consider these routes:


export const AppRoutePaths = {
  home: '',
  auth: 'auth',
  project: {
    index: 'project',
    byId: ({ id }: { id: string }) => `${id}`, 
  }

Enter fullscreen mode Exit fullscreen mode

If I want to link to auth, I can use:


<Link href={AppRoutePaths.auth} ... />

Enter fullscreen mode Exit fullscreen mode

But what if I'm on the auth route and want to link to byId inside project?


<Link href={AppRoutePaths.project.byId({ id: 'id' })} ... />

Enter fullscreen mode Exit fullscreen mode

Without the createAppRouterFullPath function, this would redirect to localhost:3000/auth/:id instead of localhost:3000/project/:id. The function takes care of joining nested routes with their parent.

Now, how do you use it? Check this out:


const router = useMemo(
  () =>
    createBrowserRouter([
      {
        errorElement: <ErrorBoundary />,
        element: <Layout />,
        children: [
          {
            path: AppRoutePaths.home, // here
            index: true,
            element: (
              <LazyRoute>
                <HomePage />
              </LazyRoute>
            ),
          },
          // ... (other routes)
        ],
      },
    ]),
  []
);

Enter fullscreen mode Exit fullscreen mode

I've also thrown in a handy function to add '/' in front of routes when needed, preventing them from becoming relative to the current URL:


export function withSlashPrefix(path: string) {
  return `/${path}`;
}

Enter fullscreen mode Exit fullscreen mode

Now linking buttons to pages is a breeze:


<Link href={withSlashPrefix(AppRoutePaths.home)}>
    <Button>GoToHome</Button>
</Link>

Enter fullscreen mode Exit fullscreen mode

It's just one of my explorations; I work with React every day, so I frequently encounter issues and discover reasons to build or update things. This is one of those instances.

Voila! Happy routing!

Top comments (0)