Skip to main content
TASIOMIND.DEV — OPERATIONAL▸▸▸FULL STACK DEVELOPER @ GWQ SERVICEPLUS AG▸▸▸FOUNDER — K8SGPT.AI▸▸▸OPEN SOURCE: ACTIVE▸▸▸DISTRIBUTED SYSTEMS / KUBERNETES / AI▸▸▸RUST + GO + PYTHON▸▸▸FIELD TESTED / STATUS — NOMINAL▸▸▸LOCATION: EUROPE/BERLIN▸▸▸TASIOMIND.DEV — OPERATIONAL▸▸▸FULL STACK DEVELOPER @ GWQ SERVICEPLUS AG▸▸▸FOUNDER — K8SGPT.AI▸▸▸OPEN SOURCE: ACTIVE▸▸▸DISTRIBUTED SYSTEMS / KUBERNETES / AI▸▸▸RUST + GO + PYTHON▸▸▸FIELD TESTED / STATUS — NOMINAL▸▸▸LOCATION: EUROPE/BERLIN▸▸▸
reactjs

Implementing React Router and Real-Time User Monitoring in React Applications

Aland Baban · August 2020 · 6 min read
[ contents ]

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.

code
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:

code
yarn start

This will open the application at http://localhost:3000/.

Boilerplate React App

Creating the First Route

To create a route, import Router and Route from react-router-dom in your src/App.js file.

code
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.

code
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.

code
function App() {
  return (
    <Router history={history}>
      <Route path="/" component={Home} />
    </Router>
  );
}

Create a Home component in src/components/Home.js:

code
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.

Home Component Rendered

Adding a Second Route

Create another component, src/components/About.js, with similar content.

code
import React from 'react';

export default function About() {
  return (
    <div>
      <h1>About</h1>
    </div>
  );
}

Add it as a new route in App.js:

code
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.

code
<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.

code
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.

code
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.

Navigation Demo

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.

code
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.

code
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.

code
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.

code
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.

Post List Post Detail

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.

New Experience App

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

Create App

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.

code
<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.

code
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.

code
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.

Dashboard Overview Page Load Details 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.