How to use socket.io-client correctly in React app
Tags: socket, react, javascript, webdev
Published: 2020-12-16 17:56:13

---
title: How to use socket.io-client correctly in React app
published: true
description: In this article, I want to describe how to use socket io client correctly using React hooks.
tags: socket, react, javascript, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/9ukpln29sl8qt01w9fea.png
---

## Background

The following is my first blog to achieve 8k+ view and 1st in Google SERP rank. However, it has some concerns and I decided to rewrite it.
{% link https://dev.to/bravemaster619/how-to-prevent-multiple-socket-connections-and-events-in-react-531d %}

In this article, I used global `socket` variable to manage socket events in a React app. Like the following:

```javascript
// service/socket.js
export const socket = socketio.connect(SOCKET_URL);
// elsewhere
import {socket} from "service/socket";
```

However, fellow devs recommended to use React context API in their comments. And I began to think that using global variable is not a React-way either. (Although I believe that works too. Because socket does not change its state). 

I updated my previous article, but I think it needs more explanation. So I decided to write an article that shows how to use React context API to manage one global socket instance.

### 1. Create Socket Context

We will use [useContext](https://ko.reactjs.org/docs/hooks-reference.html#usecontext) hook to provide SocketContext to entire app.

Create a file in `context/socket.js`:

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

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

### 2. Use socket context and provide a value

Add SocketContext provider at the root of your project or at the largest scope where socket is used:

```javascript
import {SocketContext, socket} from 'context/socket';
import Child from 'components/Child';

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

### 3. Now you can use socket in any child component

For example, in `GrandChild` component, you can use socket like this:

```javascript
import React, {useState, useContext, useCallback, useEffect} from 'react';
import {SocketContext} from 'context/socket';

const GrandChild = ({userId}) => {

  const socket = useContext(SocketContext);

  const [joined, setJoined] = useState(false);

  const handleInviteAccepted = useCallback(() => {
    setJoined(true);
  }, []);

  const handleJoinChat = useCallback(() => {
    socket.emit("SEND_JOIN_REQUEST");
  }, []);


  useEffect(() => {
    // as soon as the component is mounted, do the following tasks:

    // emit USER_ONLINE event
    socket.emit("USER_ONLINE", userId); 

    // subscribe to socket events
    socket.on("JOIN_REQUEST_ACCEPTED", handleInviteAccepted); 

    return () => {
      // before the component is destroyed
      // unbind all event handlers used in this component
      socket.off("JOIN_REQUEST_ACCEPTED", handleInviteAccepted);
    };
  }, [socket, userId, handleInviteAccepted]);

  return (
    <div>
      { joined ? (
        <p>Click the button to send a request to join chat!</p>
      ) : (
        <p>Congratulations! You are accepted to join chat!</p>
      ) }
      <button onClick={handleJoinChat}>
        Join Chat
      </button>
    </div>
  );
};
```

OK, here are some explanations:

#### What is `useContext`?

- `useContext` provides a React way to use global state
- You can use context in any child component
- Context values are states. React notices their change and triggers re-render.

#### What is `useCallback`? Why did you put every handlers inside `useCallback`?

- `useCallback` prevents reassigning whenever there is state update
- Functions will be reassigned only when elements in the second argument are updated
- Since we passed an empty array to second argument, functions are assigned for only once
- You may forget (or don't bother) to use `useCallback`. But you may face serious performance issues if there are many states and components in your project

#### What is `useEffect` and that `[socket]` array provided as  the second argument?

- The second argument is called dependency array. React will watch dependency array elements and whenever one of them is updated, the first argument function will be executed.

- If you omit dependency array in `useEffect`, the function will be executed whenever there is a state update.

- If the dependency array is an empty array, the function will be executed only once.

- In React functional component, you can write `componentDidMount` and `componentWillUnmount` alternatives in the following way:

```javascript
useEffect(() => {
  // here is componentDidMount
  return () => {
    // here is componentWillUnmount
  }
}, []);
```

- It is strongly recommended to put every state that's used in the first argument function to the dependency array. 


### BONUS

If you want to use JWT token to authenticate socket connections, you can do like the following:

```javascript
const getSocket = () => {
  const token = getAuthToken(); // get jwt token from local storage or cookie
  if (token) {
    return socketio.connect(SOCKET_URL, {
      query: { token }
    });
  }
  return socketio.connect(SOCKET_URL);
};
```

Then in socket server, you can get jwt token like the following:

```javascript
import SocketIO from "socket.io";

const io = new SocketIO.Server(expressApp);
const jwtMiddleware = (socket, next) => {
  const {token} = socket.handshake.query;
  // verify token
};

io.use(jwtMiddleware);
```