Reverse patterns to URL. React router Config.

ihormaslov

Ihor Maslov

Posted on March 15, 2021

Reverse patterns to URL. React router Config.

In this post, I would like to introduce my approach to "Named URLs" for React Router.

Motivation

I used to use Django's URLs reverse function. This function is beneficial when you need to get an actual URL using a named URL pattern or callable view object.
I want to use a similar approach with React Router.

Problems

The problems I am trying to solve are:

  1. Avoid hard-coded URLs. In the most examples I found, URLs hard-coded in Link. I feel like this can lead us to broken links during refactoring, etc.
  2. Missing URL params. It is difficult to identify Hard-coded links with missed params until you click on them.

Solution

The project directories are structured this way.

The Reverse implementation.

// src/shared/utils/namedUrls.js

import { compile } from 'path-to-regexp';

export class RoutePath {
  reverse(params) {
    const reversed = compile(this.pattern);
    return reversed(params);
  }

  constructor(pattern, component) {
    if (!pattern || !component) throw new Error('`pattern` and `component` are required');
    this.pattern = pattern;
    this.component = component;
  }
}
Enter fullscreen mode Exit fullscreen mode

This class helps us build a route that knows how to build a link using given parameters and patterns.

The usage.

In the app directory.

// src/apps/account/routes.js

import SignInPage from 'apps/account/pages/SignIn';
import UserPage from 'apps/account/pages/User';
import { RoutePath } from 'shared/utils/namedUrls';

const basePath = '/account/';
export default {
  signIn: new RoutePath(`${basePath}sign-in/`, SignInPage),
  user: new RoutePath(`${basePath}user/:id/`, UserPage),
};
Enter fullscreen mode Exit fullscreen mode

In the main routes.js.

// src/routes.js

import { prepareRoutes } from 'shared/utils/namedUrls';

import accountRoutes from './apps/account/routes';

export const routes = {
  accountRoutes,
};

export const preparedRoutes = prepareRoutes(routes);
Enter fullscreen mode Exit fullscreen mode

In components

import React from 'react';
import { Link } from 'react-router-dom';
import { routes } from 'routes';

const SomeComponent = () => (
  <>
    <Link to={routes.accountRoutes.signIn.reverse()}>Sign In</Link>
    <Link to={routes.accountRoutes.user.reverse({ id: 1 })}>User</Link>
  </>
);

export default SomeComponent;
Enter fullscreen mode Exit fullscreen mode

Rendered links are:

<a href="/account/sign-in/">Sign In</a>
<a href="/account/user/1/">User</a>
Enter fullscreen mode Exit fullscreen mode

Error handling

I didn't implement any additional error handling as I am satisfied with the path-to-regexp app's error handling.
If you miss some URL pattern parameters, you will find errors like the below in the browser console.

index.ts:337 Uncaught TypeError: Expected "id" to be a string
    at index.ts:337
    at RoutePath.reverse (namedUrls.js:12)
    at App (App.js:62)
Enter fullscreen mode Exit fullscreen mode

I suppose this will be enough to warn developers that they missed the URL pattern's parameters. And I feel like these errors should be helpful during e2e testing.

Feedback is welcome!

💖 💪 🙅 🚩
ihormaslov
Ihor Maslov

Posted on March 15, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

React Query meets React Router
javascript React Query meets React Router

September 12, 2022

Nested Routes- React Router
javascript Nested Routes- React Router

May 30, 2022

React Router: Basics
react React Router: Basics

March 23, 2022