Skip to content

Chapter 6 - Create a React Context to connect to the backend with Socket.IO

In this chapter, you'll create a React Context to connect to the backend with Socket.IO.

Info

All the following steps will be executed in the frontend directory.

In a new terminal, you can switch to the frontend directory with the following command.

In a terminal, execute the following command(s).
cd frontend

Steps

Install Socket.IO client for the frontend

Install Socket.IO client for the frontend with the following command.

In a terminal, execute the following command(s).
npm install --save socket.io-client

Create the WebSocket Provider

As mentioned in a previous chapter, a provider allows to give access to some shared properties to the children of the provider. In this case, you'll create a WebSocket provider to connect to the Socket.IO gateway.

frontend/src/components/websocket-provider.tsx
import { useEffect, useMemo } from "react";
import { Socket, io } from "socket.io-client"; // (1)!

function WebSocketProvider({ children }: { children: React.ReactNode }): JSX.Element {
    const socket: Socket = useMemo( // (2)!
        () => io("localhost:4000", { autoConnect: false }),
        []
    );

    useEffect(() => { // (3)!
        if (!socket.connected) {
            socket.connect(); // (4)!
        }

        return () => { // (5)!
            socket.close();
        };
    }, [socket]); // (6)!

    return <>{children}</>;
}

export { WebSocketProvider };
  1. Import Socket.IO.
  2. The useMemo function allows to keep the same reference on the socket during the entire lifecycle of the component. In other words, it allows to only have one WebSocket connected to the backend at a time.
  3. The useEffect function allows to run some code only once the React component is fully initialized.
  4. If the frontend hasn't connect to the backend yet, it connects to it now.
  5. Once the React component is destroyed, this function is called to close the connection to the backend.
  6. The socket is a dependency of the useEffect function. If the reference to this variable changes, the useEffect function will be called again.

Update the main page

Update the main page to use the WebSocket provider.

frontend/src/pages/index.tsx
import { LineProvider } from "@/components/line-provider";
import { WebSocketProvider } from "@/components/websocket-provider";
import dynamic from "next/dynamic";

const Sketch = dynamic(
	() => import("../components/sketch").then((mod) => mod.Sketch),
	{
		ssr: false,
	}
);

export default function Home() {
	return (
		<LineProvider>
			<WebSocketProvider>
				<Sketch />
			</WebSocketProvider>
		</LineProvider>
	);
}

Info

Since the role of the WebSocketProvider in this chapter is only to connect with the backend server, you may ask yourself why does it needs to be the child of LineProvider and the parent of Sketch.

The answer is "You don't choose your family".

Seriously, know that it works if the components were sorted that way:

1
2
3
4
5
6
<>
	<LineProvider>
		<Sketch />
	</LineProvider>
	<WebSocketProvider />
</>

WebSocketProvider will needs to lose the {children} props, but it will connect with the backend server when accessing the http://localhost:3000.

Also, why the WebSocket needs to be in a component ? It could be in a TypeScript class, the constructor initialize the connection and methods provide a way to emit and receive message with the WebSocket connection. Yeah you're right, but experience shows that we can do better, and this tutorial shows you that way.

Check the results

Start the frontend and the backend services. Access the frontend on http://localhost:3000. You should see the exact same result as earlier.

Check the logs of your backend application. You should see the following message.

A player has connected

Reload your window. You should see the following messages.

A player has disconnected
A player has connected

If you close your window, you should see the following message.

A player has disconnected

To stop your applications, press Ctrl+C in your terminal.

Summary

Congrats! You have successfully connected your frontend to your backend! This application lacks some communication about point and the next chapter covers that! After that, the drawing application will be working.