Handling Routes In React.js | A Custom Approach
Frulow

Frulow @frulow

Joined:
Jan 2, 2021

Handling Routes In React.js | A Custom Approach

Publish Date: Jan 19 '24
0 0

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!

Comments 0 total

    Add comment