Hookrouter: A Modern Approach to React Routing

Routing in React applications using the Hookrouter

Isuri Devindi
Bits and Pieces

--

Routing is essential for Single Page Applications (SPAs) to navigate through pages and to initialize state. With React, I’m sure most of you have used react-router-dom, a variant of the Reactrouter library for routing.

However, with React hooks’ introduction, a new module known as the Hookrouter has been launched very recently as a flexible, fast router based on hooks.

This article will focus on how we can use the Hookrouter module to replicate the Reactrouter’s basic functionalities.

To demonstrate the features of Hookrouter I will be using a product store front example with four basic components namely Nav.js, Home.js, About.js, and Shop.js. Besides, the complete React app with routing using Hookrouter can be found here.

1. Defining Routes with Hookrouter vs Reactrouter

When using Reactrouter, we can define the routes as follows.

Basic routing using Reactrouter

I hope most of you are familiar with the above example, which is relatively straightforward.

However, if we implement the same using Hookrouter, we can declare the routes as an object using the useRoutes() hook.

The object keys define the paths, while values are the functions triggered when the path matches. The router checks the paths one after the other and stops after a match has been found.

Basic routing using Hookrouter

The <Route/> the component in Reactrouter has to be rendered every time, along with all the props for each route in the app. Nevertheless, with Hookrouter, the routes defined as an object can be simply passed to the useRoutes() hook.

Note: Make sure to create the route object outside the components; otherwise, the whole object will be re-created at every render.

2. Implementing Switch Functionality of Reactrouter in Hookrouter

The <Switch>is used to render routes exclusively by rendering the first child <Route> or <Redirect> that matches the location. <Switch> is usually utilized to render a 404 page when the defined navigation routes are not matched.

Let’s look at how we can use <Switch> to route to the 404 pages with Reactrouter.

Routing to an error page using the <Switch> in Reactrouter

When routing is done using the Hookrouter, the routes are rendered exclusively since they are defined in an object. Therefore, the useRoutes() hook performs the functionality of the <Switch> component by default.

For instance, to route to a 404 page using Hookrouter, we only have to pass the error we want to display or the component containing the error message for rendering, as shown below (line 17).

Routing to an error page using Hookrouter

Note: An important fact I have noticed is that in Reactrouter <Switch>is that if the path is not declared as exact, it might lead to erroneous routings in some cases.

For example, if the path to {Home} is not declared as exact, the application won’t route to any other path starting with ‘/’. As a result, the app won’t route to {About} or {Shop} components and will always route to the Home page. However, in Hookrouter, since the routes are declared as an object, explicit declarations of “exact” for paths are not necessary.

3. Navigation using Hookrouter

With Reactrouter, <Link> is used to navigate across the application. Besides, navigations can be customized and managed interactively in a React app using this.

Nav.js with <Link> from Reactrouter

The Hookrouter uses a <A> component to provide the functionality of the <Link> component. <A> is a wrapper around the HTML anchor tag <a> and is 100% feature compatible with the anchor tag.

The main difference between <A> and <Link> is that <A>pushes the URL to the history stack without loading a new page. As a result, onclick functions have to be wrapped by the <A> component to intercept the click event to stop the default behavior and push the URL on the history stack.

Nav.js with <A> from Hookrouter

4. Handling Dynamic Routes

Some components contain dynamic portions that have to be rendered based on the URL on demand. URL parameters are used to set dynamic values in a URL. In Reactrouter, placeholders are passed to the path prop starting with a colon in the <Route/> component.

To demonstrate this concept, let’s consider a list of products displayed on the application’s Shop page. The user should be directed to the Details page of a specific product when they click on it. The navigation is done dynamically, passing the product id as a placeholder in the path prop.

Dynamic routing using Reactrouter

In Hookrouter, the URL parameters can be passed in the same way as done in Reactrouter. The construct is the same.

Dynamic routing using Hookrouter

However, the Hookrouter handles the URL parameters differently.

  1. It reads the URL parameters using the keys defined in the routes object
  2. Puts them into an object, and the named parameters will be forwarded to the route result function as a combined object.
  3. The dynamic property is extracted from the props using object destructuring, and then it can be applied to the relevant component.

Therefore, as you have seen, the same result obtained using the Reactrouter can be achieved by the Hookrouter.

5. Other Features of the Hookrouter

Programmatic navigation

The navigate(url, [replace], [queryParams]) function from the Hookrouter package can be used to send users to a specific page defined by the absolute or relative URL provided. For example, to navigate to the about page, the code snippet given below can be used.

navigate(‘/about’) 

navigate() by default is a forward navigation. Therefore, a new entry in the browsing history will be created, and the user can click the back button in the browser to get back to the previous page.

Redirects

Hookrouter handles redirects with the aid of the useRedirect() hook. It takes a source route and a target route as parameters.

useRedirect('/', '/greeting');

Whenever the ‘/’path is matched, the useRedirect() will automatically redirect the user to the ‘/greeting’ route.

This hook triggers a replacement navigation intent. As a result, there will be only one entry in the navigation history. Therefore, if redirection happens from ‘/’ to ‘/greeting’ as shown in the last code snippet, the ‘/’ route will not appear in the browsing history.

Many of the other Reactrouter library features (apart from the ones discussed here) can be implemented using the Hookrouter module, such as nested routing, lazy loading components, and server-side rendering.

Besides, feel free to go through the Hookrouter documentation to learn more about this module.

Drawbacks

I have noticed that sometimes the Hookrouter doesn’t work with Strict Mode that is enabled by default in the latest versions of create-react-app.

However, you only have to remove the <React.StrictMode> component from your index.js to use Hookrouter.

<React.StrictMode>
<App />
</React.StrictMode>

Another drawback is that since this module is relatively new, it might contain some unknown and unusual bugs resulting in unexpected behaviors.

Conclusion

From the above demonstrations, it’s clear that the Hookrouter module offers a cleaner, faster, and more flexible alternative to handle routes in a React application.

It offers most of the Reactrouter library features. Therefore, I encourage you to go ahead and try it out for smaller projects for a start.

Thank you for reading!

Build anything from independent components

Say goodbye to monolithic applications and leave behind you the tears of their development.

The future is components; modular software that is faster, more scalable, and simpler to build together. OSS Tools like Bit offer a great developer experience for building independent components and composing applications. Many teams start by building their Design Systems or Micro Frontends, through shared components. Give it a try →

An independently source-controlled and shared “card” component. On the right => its dependency graph, auto-generated by Bit.

--

--

Undergraduate | University of Peradeniya | Faculty of Engineering | Department of Computer Engineering