How to prevent multiple socket connections and events in React
Tags: socket, socketio, react, spa
Published: 2020-03-22 08:44:34

---
title: How to prevent multiple socket connections and events in React
published: true
description: In this article, I'd like to share my experience in ensuring only one instance of socket connection and event bindings in React.
tags: socket,socketio,react,SPA
---
Multiple socket connections and event bindings can be easily overlooked in SPAs and can cause headaches. I'd like to share my experience of preventing them. In this article, I will use `socket.io` for Node.js backend and `socket.io-client` for React frontend.

### 1. Connect only once

Create a dedicated file for socket connection. For example, create a file in `service/socket.js`:

```javascript

import io from "socket.io-client";
import { SOCKET_URL } from "config";

export const socket = io(SOCKET_URL);
```

You can import this socket instance in other React components whenever necessary:
```javascript
import {socket} from "service/socket";

function MyComponent() => {
   return(<div></div>)
}
```
In this way, you can ensure there will be only one socket instance.

### 2. Bind and emit events only once - put them in the correct place

Consider you're building a React component that connect to a socket server when the page is loaded and show welcome message if the connection is successful. The component will emit an `HELLO_THERE` event to the server and the server will respond with warm `WELCOME_FROM_SERVER` event. Where would you place socket event binding and emiting in your React code?

```javascript
import {socket} from "service/socket";
// NOT HERE (1)
// socket.emit('HELLO_THERE');
function MyComponent() => {

   // NOT HERE EITHER (2)
   // socket.emit('HELLO_THERE');
   const [connected, setConnected] = useState(false);
   // IT IS HERE
   useEffect(() => {
      socket.emit('HELLO_THERE');
      const eventHandler = () => setConnected(true);
      socket.on('WELCOME_FROM_SERVER', eventHandler);
      // unsubscribe from event for preventing memory leaks
      return () => {
         socket.off('WELCOME_FROM_SERVER', eventHandler);
      };
   }, []);
   return (
      <div>
          { connected ? (
               <p>Welcome from server!</p>
          ) : (
               <p>Not connected yet...</p>
          ) }
      </div>
   )
}
export default MyComponent
```

- (1) This will emit the event even if `MyComponent` is not used.
- (2) This will emit the event whenever `MyComponent` is updated.

<small>* If you're using React classes, `componentDidMount` will be the right place to use sockets. `useEffect(() => {}, [])` is almost the same as `componentDidMount`</small>
<small>** Of course, `socket.emit` can go anywhere necessary in your code. However, `socket.on` should be in `componentDidMount` in most cases.</small>

### 3. If you're unsure, there is always this hack

If you still cannot figure out why does your component stupidly bind the same listener for multiple times, or if you just want to make sure bind only one listener for one event, you can resort to `socket.off`.
```javascript
socket.off('MY_EVENT', doThisOnlyOnce).on('MY_EVENT', doThisOnlyOnce);
```

### UPDATE - useContext approach

If you want to use `useContext` hook, you can do like this one:

**socket.js**

```javascript
import React from "react";
import io from "socket.io-client";
import { SOCKET_URL } from "config";

export const socket = io(SOCKET_URL);
const SocketContext = React.createContext(socket);
```

Your `app.js` should look like the following:

```javascript
import React from "react";
import SocketContext, { socket } from "context/socket";

const App = () => (
   <SocketContext.Provider value={socket}>
      <OtherComponents />
   </SocketContext.Provider>
);
```

Then anywhere in your component, you can get socket like this:

```javascript
import React from "react";
import SocketContext from "context/socket";

const OtherComponent = () => {
  const socket = React.useContext(SocketContext);
  ...
};
```

For more information, you can read my another post here:

{% link https://dev.to/bravemaster619/how-to-use-socket-io-client-correctly-in-react-app-o65 %}