Introduction:
As web developers, we often rely on libraries and frameworks to handle routing for us. In the case of a client-side application built with React, the most popular choice is probably React Router. However, there may be situations where you want to build your own custom router for various reasons such as performance, custom features, or simply for learning purposes.
In this blog post, we will explore how to build a custom React router from scratch. We will start by discussing the basics of client-side routing and the role of a router in a React application. Then, we will implement a simple router using the window.history
API and the useEffect
hook from the React Hooks API. Finally, we will see how to add additional features such as route matching, URL parameters, and programmatic navigation to our router.
Basics of Client-Side Routing:
Client-side routing refers to the process of navigating between different pages or views of a client-side application without reloading the whole page. This is in contrast to server-side routing, where the server handles the navigation and sends a new HTML document to the client on each navigation.
In a client-side application, the router is responsible for mapping the current URL to a specific view or component to be displayed. It also updates the URL when the user navigates to a different view. This way, the application can have multiple views that can be accessed through different URLs, just like a traditional website.
Building a Simple Router:
To build our custom router, we will start by creating a Router
component that will act as the root of our application. This component will have a routes
prop that is an array of objects representing the routes in our application. Each route object should have a path
and a component
property. The path
is a string representing the URL pattern of the route, and the component
is a React component that will be displayed when the route is active.
Here is an example of how our Router
component could look:
In the Router
component, we are using the useEffect
hook to listen for popstate
events on the window
object. The popstate
event is fired every time the user navigates through the history, either by clicking on the back or forward buttons of the browser or by calling the history.back()
or history.forward()
methods.
In the handleLocationChange
function, we will update the active route based on the current URL. To do this, we will loop through the routes
prop and check if the path
of each route matches the current URL. We can use the window.location.pathname
property to get the current URL and the matchPath
function from the react-router-dom
library to check if a route’s path
matches the current URL. Here is an example of how we can implement this in the handleLocationChange
function:
Now that we have the active route, we need to render the corresponding component. To do this, we can add a state variable to the Router
component to store the active route. Then, we can use this state variable to render the active route’s component in the Route
component.
Here is an example of how this could look:
With this implementation, the Route
component will render the corresponding component if the route is active, otherwise it will return null
.
Adding URL Parameters and Programmatic Navigation:
Now that we have a basic router working, we can add some additional features to it. One common feature of routers is the ability to extract URL parameters and pass them to the route’s component as props. For example, if we have a route with the path /users/:id
, we can extract the id
parameter from the URL and pass it to the component as a prop.
To implement this feature, we can modify the Route
component to extract the parameters from the URL and pass them as props to the component. We can use the matchPath
function from react-router-dom
again to extract the parameters from the URL.
Here is an example of how this could look:
Another useful feature of routers is the ability to navigate programmatically. This means that we can change the URL and the active route from within our application code, without the user clicking on a link or using the browser’s navigation buttons.
To implement this feature, we can add a navigate
method to the Router
component that updates the URL and triggers the popstate
event. We can use the history.pushState
method of the window.history
API to update the URL and the dispatchEvent
method to trigger the popstate
event.
Here is an example of how this could look:
With this implementation, we can call the navigate
method from anywhere in our application to update the URL and trigger a navigation.
Conclusion:
In this blog post, we have seen how to build a custom React router from scratch. We started by discussing the basics of client-side routing and the role of a router in a React application. Then, we implemented a simple router using the window.history
API and the useEffect
hook from the React Hooks API. Finally, we added additional features such as route matching, URL parameters, and programmatic navigation to our router.
While building a custom router can be a fun and educational exercise, in most cases it is probably easier and more practical to use an existing router library such as React Router. However, understanding how routers work and being able to build your own can give you a deeper understanding of how client-side routing works and give you more control over your application’s routing behavior.
Leave A Comment