Algobook
- The developer's handbook
mode-switch
back-button
Buy Me A Coffee
Fri Apr 07 2023

Implement an Active users component with live updates through Websockets

In todays tutorial, we will create a very simple component in React that are displaying the current active users on a website. The number will be updated through push updates using websockets.

We will create the following

  • A React component
  • Websocket client that will trigger updates on our React component
  • A Websocket server in Nodejs

So in all, we will have two applications. One server and one client.

Final result

Below is the final result. For each session we create, the number will increase, and for every session that ends, the number will decrease.

demo

What is a Websocket?

Websocket is a communication protocol that enables a two way interactive communication between a client and a server. The communication will remain open and listen for messages, compared to a http request that will end after the response is received. This enables powerful features and amazing possibilities for us to create really cool features.

In this guide, we will only just touch the subject and make it as basic as it gets. But we will provide much more content regarding websockets and do more advance examples in the near future.

Implement our websocket server

Let's start with our server. First we need to setup our project.

npm init npm install websocket touch index.js

Create our websocket server

In our index.js file:

const WebSocketServer = require("websocket").server; const http = require("http"); const PORT = 8085; const server = http.createServer(); server.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`); }); wsServer = new WebSocketServer({ httpServer: server, autoAcceptConnections: true, }); wsServer.broadcastOnlineUsers = () => { wsServer.connections.forEach((client) => { client.send(JSON.stringify({ activeClients: wsServer.connections.length })); }); }; wsServer.on("connect", (ws) => { console.log( `A new connection has been setup, total clients: ${wsServer.connections.length}` ); wsServer.broadcastOnlineUsers(); ws.on("close", () => { console.log( `Removed client with id ${ws.id}. Total clients: ${wsServer.connections.length}` ); wsServer.broadcastOnlineUsers(); }); });

Some notes

  • We are setting up a http server that we will use to mount the websocket server.
  • autoAcceptConnections: true for accepting all origins. This should not be true in production. Read more on CORS.
  • Creating a function, broadcastOnlineUsers(), for sending the current amount of active users to all our clients.
  • wsServer.on("connect") listener will trigger on each client that are connecting. We will call our broadcastOnlineUsers() to tell the client about the new number of active users.
  • ws.on("close") will do the opposite. It will trigger when a client disconnects and then call broadcastOnlineUsers() with the updated number of active users.

That's it. Now start the server with:

node index.js

Implement our client

Now it's time to write our client. For this guide, we will use a React application. But with some tweaking on the component, any framework would work.

  • Create WebsocketClient.js
  • Create ActiveUsers.jsx
  • Create ActiveUsers.module.css or just a css file

WebsocketClient.js

class WebsocketClient { _listeners = []; _wsClient = null; constructor() { this._wsClient = new WebSocket("ws://localhost:8085"); this._wsClient.onmessage = this.onMessage.bind(this); } subscribe(id, callback) { const existingListener = this._listeners.find( (listener) => listener.id === id ); if (existingListener) { console.log("Already subscribing"); return; } else if (!id || !callback) { console.log("Id and Callback must be provided"); return; } this._listeners.push({ id, callback }); } onMessage(event) { this._listeners.forEach((listener) => listener.callback(JSON.parse(event.data)) ); } } export default new WebsocketClient();

That's it for our Websocket client class.

Some notes

  • _listeners will be all components that are listening. In our example, it will only be one but you might want to have it in multiple places in your app - so we built it with that in mind.
  • _wsClient is our websocket client
  • subscribe() will be called by the components that are interested in the active users count. It should get an id and a callback function that will receive the messages from the websocket server
  • onMessage() will be triggered for every message from the websocket server and our listeners callback functions will be called
  • export default new WebsocketClient(); will make sure that only one instance is created. Read more on Singleton pattern here.

ActiveUsers component

import { useEffect, useState } from "react"; import websocketClient from "./WebsocketClient"; import styles from "./ActiveUsers.module.scss"; export const ActiveUsers = () => { const [activeUsers, setActiveUsers] = useState(0); useEffect(() => { websocketClient.subscribe("homePage", (msg) => { setActiveUsers(msg.activeClients); }); }, []); return ( <div className={styles.container}> <div className={`${styles.badge} ${activeUsers < 1 ? styles.offline : 0}`} /> <span className={styles.text}>{`${activeUsers} users active`}</span> </div> ); };

That's it for this component. In our useEffect() hook we will set up our subscription and our callback will update our activeUsers state with the current value which will be displayed in the component. If the value is 0, we will apply another style for making the badge red.

Let's give our component some styling

.container { display: flex; align-items: center; gap: 1rem; .badge { background-color: green; width: 12px; height: 12px; border-radius: 50px; } .offline { background-color: red; } .text { font-size: 16px; } }

That's it for our client. Now it should increase the value for new client that connects. Since we are on localhost, the way to test it out it to open a new tab or browser window.

Outro

As stated in the beginning, this is a very simple example of what websockets has to offer. We will have more guides on this topics with more advanced examples. But I just wanted to get you guys that haven't worked with websockets onboard with the basics first.

I really hope you enjoyed this tutorial, and stay tuned for more advanced stuff in the near future!

signatureFri Apr 07 2023
See all our articles