Implementing React Router and Real-Time User Monitoring in React Applications
Single-page applications (SPAs), commonly built with React, require a robust routing mechanism to manage navigation between different views without reloading the entire page. This dynamic routing is essential for a seamless user experience.
This tutorial provides a comprehensive guide to implementing client-side routing in a React application using React Router, a popular library for this purpose. Additionally, it demonstrates how to integrate a real-user monitoring (RUM) tool, Sematext Experience, to gain insights into application performance and user behavior.
Prerequisites
Before you begin, ensure you have the following installed:
- Node.js (version 12.x.x or higher)
- A package manager such as npm, yarn, or npx
- Basic knowledge of JavaScript, ES6, and React
- A Sematext account (a trial version is sufficient)
Getting Started
Begin by creating a new React project using npx. Once the project is generated, navigate into the directory and install the react-router-dom library.
npx create-react-app react-router-demo
cd react-router-demo
yarn add react-router-dom
The React Router library (version 5) consists of three packages: react-router (the core), react-router-dom (for web applications), and react-router-native (for React Native). This tutorial uses react-router-dom.
To view the initial React application, run the development server:
yarn start
This will open the application at http://localhost:3000/.

Creating the First Route
To create a route, import Router and Route from react-router-dom in your src/App.js file.
import React from 'react';
import { Router, Route } from 'react-router-dom';
We will use the low-level Router component, which requires a history object to be passed manually. This object will also be used later for the monitoring tool.
import { createBrowserHistory as createHistory } from 'history';
const history = createHistory();
A Route component renders a specific UI component when its path prop matches the current URL.
function App() {
return (
<Router history={history}>
<Route path="/" component={Home} />
</Router>
);
}
Create a Home component in src/components/Home.js:
import React from 'react';
export default function Home() {
return (
<div>
<h1>Home Page</h1>
</div>
);
}
Import this component into App.js and view the result in your browser.

Adding a Second Route
Create another component, src/components/About.js, with similar content.
import React from 'react';
export default function About() {
return (
<div>
<h1>About</h1>
</div>
);
}
Add it as a new route in App.js:
import About from './components/About';
function App() {
return (
<Router history={history}>
<Route path="/" component={Home} />
<Route path="/about" component={About} />
</Router>
);
}
When you navigate to /about, you will notice that both components are rendered. This is because / matches both paths. To fix this, use the exact prop on the Home route to ensure it only matches the root path.
<Route path="/" exact component={Home} />
Using the Switch Component
The Switch component renders only the first Route that matches the current location. This is useful for handling exclusive routes and redirects. Wrap your routes inside a Switch.
import { Router, Route, Switch } from 'react-router-dom';
function App() {
return (
<Router history={history}>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Switch>
</Router>
);
}
Adding a Navigation Bar
To navigate between pages without a full browser refresh, React Router provides the NavLink component. Add a simple navigation menu in App.js.
import { Router, Route, Switch, NavLink } from 'react-router-dom';
function App() {
return (
<Router history={history}>
<nav style={{ margin: 10 }}>
<NavLink exact to="/" style={{ padding: 10 }}>
Home
</NavLink>
<NavLink to="/about" style={{ padding: 10 }}>
About
</NavLink>
</nav>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</Switch>
</Router>
);
}
This will render a navigation bar allowing you to switch between the Home and About pages.

Adding Route Parameters
Dynamic routes can be created using URL parameters like :id. This is useful for displaying detailed views of specific items, such as blog posts.
Create a new component src/components/Posts.js and define a static array of post data.
import React, { useState } from 'react';
import { Link, Route } from 'react-router-dom';
const POSTS = [
{ id: 1, title: 'Hello Blog World!' },
{ id: 2, title: 'My second post' },
{ id: 3, title: 'What is React Router?' }
];
Next, create a Child component that will render the details of a single post. It uses the match object prop, which contains information about how the route matched the URL, including URL parameters.
function Child({ match }) {
return (
<div>
<h3>ID: {match.params.id}</h3>
</div>
);
}
The main Posts component will render a list of post links. Each link will navigate to a dynamic route /posts/:id. A nested Route will render the Child component for the selected post.
export default function Posts() {
const [posts, setPosts] = useState(POSTS);
return (
<div className="posts">
<h1>Posts List</h1>
<ul>
{posts.map(post => (
<li key={post.id}>
<Link to={`/posts/${post.id}`}>{post.title}</Link>
</li>
))}
</ul>
<Route path="/posts/:id" component={Child} />
</div>
);
}
Finally, add the /posts route and a corresponding NavLink in App.js.
import Posts from './components/Posts';
function App() {
return (
<Router history={history}>
<nav style={{ margin: 10 }}>
<NavLink exact to="/" style={{ padding: 10 }}>Home</NavLink>
<NavLink to="/about" style={{ padding: 10 }}>About</NavLink>
<NavLink to="/posts" style={{ padding: 10 }}>Posts</NavLink>
</nav>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
<Route path="/posts" component={Posts} />
</Switch>
</Router>
);
}
Navigating to /posts will display the list, and clicking a post will show its ID.

Real User Monitoring with Sematext
Integrating a monitoring tool can provide valuable insights into your application's performance and user experience. Sematext Experience allows you to track page load times, HTTP requests, UI interactions, and application crashes.
Configure a Sematext Monitoring App
Log in to your Sematext account, create a New App, and select Experience.

Enter a name for your app, select the "About Website" option for SPAs, and click "Continue".

Installing Monitoring Scripts
You will be provided with installation scripts. Add the first script to the <head> section of your public/index.html file. This script contains your unique application token.
<script type="text/javascript">
(function (e, r, n, t, s) {
// ... Sematext script content ...
})(window, document, 'script', '//cdn.sematext.com/rum.js', 'strum');
</script>
<script type="text/javascript">
strum('config', {
token: 'YOUR_TOKEN_HERE',
receiverUrl: 'https://rum-receiver.sematext.com'
});
</script>
Next, add the routeChange event listener to your src/App.js file, right after defining the history object. This is essential for SPAs as it tracks navigation events that don't involve a full page reload.
history.listen((location, action) => {
if (action !== 'REPLACE') {
window.strum('routeChange', window.location.href);
}
});
Testing the Monitoring Tool
Build your React application for production and serve it locally.
yarn build
npx serve -s build
Navigate through the different routes of your application. After a few moments, you will see performance data appear in your Sematext dashboard. The dashboard provides an overview of page load times, resource downloads, and user demographics.

Conclusion
Real-time user monitoring offers a significant advantage for SPAs, allowing you to identify performance bottlenecks and improve the user experience. Integrating tools like Sematext Experience with React Router provides a powerful combination for building and maintaining high-quality web applications.