Building a Visit Counter with Redis and React

April 15, 2021

4 min read999 views

Building a Visit Counter with Redis and React

Redis as a database is often underestimated these days. It is commonly used for caching systems but on its own is a very powerful database. It can be used as an alternative to Firebase and MongoDB.

In this article, I will show you how we can leverage its speed and data structure capabilities to craft a visit counter component.

Setting Up the Redis database

We have to create an account in Redis Labs to start to configure the Redis database on the cloud.

Why did I choose Redis Labs?

  • They are behind the development of Redis, so naturally, they offer the best tooling and the latest updates for this database engine.
  • 300MB of storage is available at no cost, more than sufficient for our needs.
  • An uptime of 99.999% — which is impressive!
  • Millisecond data processing.

After creating your account, the next step is to set up the Redis Cloud instance as a new subscription in your account. You can check this video for more details.

When you database is ready, you need to go to the config tab and copy the Endpoint and Password values.

Connecting to Redis instance from a serverless backend

We need now a npm library to work as a client between Redis and our app. I used ioredis library because it has async functions and the feature of sending multiple commands at the same time, that we'll see later. Begin by creating a file with the basic setup to connect to our Redis instance

lib/redis.js
const redis = require("ioredis");

function Redis() {
  const conn = {
    port: process.env.REDIS_PORT,
    host: process.env.REDIS_URL,
    password: process.env.REDIS_PSW
  }
  return new redis(conn);
}

export default Redis;

Exposing an api service

Next, define the API route and its logic for storing and retrieving the number of users visiting a specific page. I'll use Next so we are going to create the following file.

pages/api/views/[slug].js
import client from 'lib/redis';
const redis = client();

export default async (req, res) => {
  const redis = client();
  const forwarded = req.headers['x-forwarded-for'];
  const ip = forwarded ? forwarded.split(/, /)[0] : req.connection.remoteAddress;
  let members = [];
  await redis
    .pipeline()
    .sadd(req.query.slug, ip)
    .smembers(req.query.slug)
    .exec((err, results) => {
      members = results[1][1];
    });
  redis.quit();
  const n = members.length;
  return res.status(200).json({
    total: n
  });
};

From the above, we can see a few things:

  • /api/views/:slug — it'll we the API URL expose to our frontend. It returns the number of unique users who visited a specific URL (slug).
  • We get the IP client to save it as a unique id and sum a visit on that page.
  • We are using a pipeline function to send multiple commands to Redis in only one transaction.
  • Redis has multiple commands to manipulate the data. We are using SADD to have a list of unique IPs for each page and not repeat the visit for each time that that user comes back to that page. And to retrieve the list we are using smembers.
  • The IP list from a specific page is saving in the variable members when we call the function exec.
  • Finally, we count the list of IPs from that page to know how many users visited it and return that number.

Building the React component

The final step is to code the component that will fetch the data and display the visit count.

PageviewsCounter.js
import useSWR from 'swr';
import { fetcher } from '@/lib/utils';

export default function PageviewsCounter({ slug }) {
  const { data } = useSWR(`/api/views/${slug}`, fetcher);
  const views = data?.total;

  if(views)
    return `${views} views`;
  return <><span className="line-through">999</span> views</>
}

As we can see, the component receives the slug of the page as a prop and it is using SWR library to improve the speed and cache for the fetch of the data.

Conclusion

In a few simple steps, we learned how to build a visit counter and store the data in our backend using Redis, without relying on external services like Analytics

Also we did get advantage of commands like SADD where in a native way it supports creating a list of non repeatable values to save the ip's of the users who visit each page.

You can see working this component, in the right corner below the headline of this post.