Redux middleware and how to use it with WebSockets

React

Middleware is a great place to connect to WebSockets if you use Redux. This article explains what the Redux Middleware is and how to use it with WebSockets.

In this blog, we also talk a lot about various backend technologies such as Express. One of the concepts popular there is middleware. In redux, it serves a similar purpose. If you want to know more about Express, check out TypeScript Express tutorial #1. Middleware, routing, and controllers

Here, we use Redux Toolkit with TypeScript. To get the same starting template, run .

The idea behind Redux middleware

Middleware allows us to add logic between the moment the user dispatches the action and when it reaches the reducer. One of the most straightforward use-cases for the middleware is logging.

Something that might be a bit confusing is that in Redux, middleware uses currying. It is a technique that involves breaking down a function that takes multiple arguments into a chain of functions that take only one argument each. Dan Abramov justifies it by the fact that we might want to use the JavaScript closures to our advantage. While not everyone agrees with this design decision, it might not be worth creating a breaking change to fix it at this point.

To understand it, let’s create a simple example.

loggerMiddlewarre.tsx

We could write the above code in a shorter way, but let’s be very explicit for now.

When we add the above middleware to our store, it results in logging every action we dispatch.

Chaining middleware

The argument is the most crucial thing to understand in the above code. Since we can have multiple middlewares, the function invokes the next one in the chain. If there are no middlewares left, it dispatches the action.

If we wouldn’t call the function, the action wouldn’t be dispatched.

Let’s add another example from the official documentation to visualize it better.

crashMiddleware.tsx

In this article, we use the Redux Toolkit. It adds some middleware to our store out of the box. To add new middleware while retaining the default ones, we can use the function as the documentation suggests.

store.tsx

The comes bundleded with the template mentioned at the top of this article.

Thanks to the fact that we’ve added before the , it executes first.

If we wouldn’t call the function in the , the would never run and the action wouldn’t be dispatched.

Using WebSockets with middleware

In API with NestJS #26. Real-time chat with WebSockets, we’ve created a backend for a chat application using socket.io. We can see that there are a few events that can happen. Let’s create an enum that contains all of them:

Even though in this article we use socket.io, the could would be very similar with barebones WebSockets.

chatEvent.tsx

Establishing a connection

To establish a connection, we need to have the URL of our backend application. A good way to store it on the frontend is through the environment variables.

.env

react-app-env.d.ts

Let’s also define the basics of our slice with the basic actions.

chatSlice.tsx

The last part of establishing a connection is to create middleware. The API we’ve created in this article needs authentication through cookies. To handle it, we need the argument.

chatMiddleware.tsx

Calling the function is how we can check if the action matches the one defined in the slice.

Our application establishes a connection through WebSockets when the user dispatches the action.

Sending chat messages and receiving them

All of the messages from our backend have a particular data structure. So let’s create an interface that matches it.

chatMessage.tsx

Now that we have the above interface, we can use it in our slice.

chatSlice.tsx

The last part of sending and receiving messages is to listen to all of the events and dispatch them.

chatMiddleware.tsx

In the above code, we do the following:

  • Emit the event as soon as the application establishes the connection.
  • Listen to the event that the backend emits in response to the event.
  • Emit the event when the user dispatches the action.
  • Listen to the event the backend emits when any of the users send a message.

Summary

In this article, we’ve explained what the middleware is in the context of Redux. When doing that, we’ve used Redux Toolkit and TypeScript. Since a middleware exists for the whole lifetime of our application, it is a good place to connect to the WebSocket. A middleware also has access to the current state and can dispatch actions. It can react to incoming messages and emit them when the user dispatches an action.

Subscribe
Notify of
guest
6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Degoke
Degoke
2 years ago

Thank you, this was really helpful

George
George
2 years ago

Bless you for writing this. As of Jan 2022, it was the only seriously helpful article I could find about writing websockets with Redux, TypeScript, and setting up the store with Redux Toolkit’s configureStore.

Last edited 2 years ago by George
Nicolas
2 years ago

Thanks a lot for this nice article, as @George said it’s precious to find that kind of setup description, it’s working as good as described even if I don’t use socket.io but vanilla

roger
roger
2 years ago

I’ve searched far and wide, this is an awesome article, thanks for this. Nice, clean well documented code.

David
1 year ago

Hello, not sure if this thread is still alive and not hope for some response, but what about unsubscribing from events? should we or not?

Ilya
Ilya
1 year ago

help please!! Not working, startConnecting.match(action) always false, so socket not created