Designing a WebSocket Client With Notifications in ReactJS | Reformers ReactJS Implementation Strategy

Uddeshya Singh
Geek Culture
Published in
6 min readMar 25, 2021

Welcome to the third and final part of the Re-Formers project (Collaborative form editor using WebSockets). This post is about a WebSocket client which handles the user interaction with our server. You can find the other posts in the series right here:

  1. Collaborative form editor using WebSockets | Web Sockets in Golang and React
  2. Designing a WebSocket server in Golang | Reformers backend implementation strategy
  3. Designing a WebSocket client with notifications in ReactJS | Reformers frontend implementation strategy

TL;DR 🤷

I created a client in ReactJS to interact with our WebSocket server complete with notification functionalities and WebSocket connection handling with the backend. You can check out the client here: Re-Formers Client with the GitHub source code present here: uds5501/re-formers

Thought Process 🧠

So, we require a client to interact with our WebSocket server. But what could be better than our good old ReactJS!

The mind map in my head was to create a client that can offer the following functionalities

  1. Maintain a constant connection with the WebSocket server.
  2. Handle the name and color combination which server assigns us and store it securely for future usage.
  3. Handling live notifications as users join/leave the room
  4. Handling live “users in the room” status
  5. Handling live question edits and version displays.
  6. Provide an option to logout the user on its own according to the server’s instructions or by clicking a simple logout.

And this client handles just that!

Wireframe of the UI 🗺️

You can find the UI screens being broken down into roughly 4–5 frames. Out of which I have decided to elaborate upon 4 of them and you can see them here. (The explanation about which component does what is given within the pictures)

User Entry Screen

User wall

User wall with a question🗺️

Editing a question

Techstack explanation 🧑‍🏫

I am using classic ReactJS (with create-react-app as the bootstrap) for the base of the entire application. To get a sleek dark-themed UI, I turned to Material-UI. To handle the promises and request-based services, I have used axios. To handle WebSocket connections I have utilized classic WebSocket API. To handle event emissions for notifications, I am using event-emitter. The last distinct package being used is universal-cookie to store and retrieve the entry token as and when required.

How is the WebSocket connection handled? 🔌

WebSocket connection is handled in App Component. On the initialization, I create a new WebSocket() object connecting it to the appropriate endpoint on the server. Once that is connected, we bind three particular connections to our WebSocket client.

  1. openEventListener
  2. incomingMessageListener
  3. closeSocket

openEventListener is used when the web socket connection is established but the client is not yet authenticated. the client sends a stored entry token from the cookies (if present) and waits for the server’s confirmation whether the user can be provided entry or not.

incomingMessageListener is used to handle incoming messages by the server. The incoming message is first parsed in JSON format and according to what the MessageType is, a messageHandler is called to take the messageData and perform an appropriate action.

closeSocket is used to handle graceful closing of the web socket connection. Upon closing, the application automatically tries to establish a connection again with the server every 5 seconds if the client did not log out on its own accord.

Notifications? This was painful. 🔔

Notification Handler was a real head-scratcher in this application. The thing is one could’ve opted for any of the three methods to show notifications to the user.

  1. Push Notifications
  2. Custom Notifications
  3. Snackbar Notifications

The push notifications sound amazing, and they indeed are so, but imagine ~30 users logged into a single room and editing multiple questions, with new users joining and existing ones leaving. This would create a lot of notifications and unless you want to spam the hell out of a client’s browser, this didn’t seem like a good solution. Sure, you can turn off notifications entirely for the website but I didn’t want to give that option either, I wanted the users to have an all-round experience with the notifications.

Snackbar notifications

I ended up using the Snackbar notification method. One could’ve used custom notifications too but frankly, I am too lazy to re-implement the wheel from scratch so Snackbar it is.

Snackbar notification component

The notify method emits a notification event (this method is supposed to be called by messageHandler upon receiving a notification request), now this will call showNotif method which will show the notification for 3 seconds and then set the state of the component back to the original situation. If there is already a notification being shown, it’ll give 0.5 seconds for it to collapse and be replaced with a new notification.

Question edit workflows, a mini thread 🧵

Now allow me to elaborate a bit on how is this client handling changes in question workflows.

Adding a new question

To add a new question, the user has to click on “Add New” button in the UI which will open a new dialogue box. Once the question details are filled up, the data is sent over to the server where one of the question edit handling threads takes in the request and waits till the mutex lock to the question array is available.
Once the mutex lock is assigned to this thread, a new question is created with the obtained details, and a subsequent thread in the server returns confirmation and a new question list to be rendered.

Flow Diagram for adding a new question

Editing a question

To edit an existing question, the user needs to ask for the edit hook first. The server ensures that the edit hook can be given to the user if and only if the following conditions hold true:

  • The user does not have an edit hook already assigned.
  • The question being considered is not being deleted.

If these conditions are true, we simply go ahead and assign the hook to the client and a new dialogue opens where one can edit the question details. Once that is done, the data is sent over to the server and once again the question handler threads wait for the mutex lock to be assigned to them, upon assignment, a new version of the question is created and broadcasted to the client for re-rendering.

An important thing to ask is What if the user has an edit lock assigned, and then the client disconnects from the web socket or refreshes his/her page?
The solution used is quite simple, the moment either of the above events is simply unassigning any hook assigned to that particular client (mapped via entry token).

Conclusion ✅

So you made it this far! Thanks for reading up on all the posts.
To conclude, I’d like to say that WebSockets is an amazing tech for real-time application processing and reduces a lot of polling overhead and we just saw how can we handle live connections among multiple users (albeit, it’s a bit slow and can definitely be more optimized using broadcasts via multiple threads)

Resources 📚

--

--

Uddeshya Singh
Geek Culture

Software Engineer @Gojek | GSoC’19 @fossasia | Loves distributed systems, football, anime and good coffee. Writes sometimes, reads all the time.