Reverse patterns to URL. React router Config.
Ihor Maslov
Posted on March 15, 2021
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:
-
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. - 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;
}
}
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),
};
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);
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;
Rendered links are:
<a href="/account/sign-in/">Sign In</a>
<a href="/account/user/1/">User</a>
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)
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!
Posted on March 15, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.