Creating a nextjs chat app for learning to integrate sockets
Tags: nextjs, sockets, personal, webdev
Published: 2024-06-26 01:22:57

Hi everyone in this post I will share with everyone my personal experience building a chat application in nextjs. To practice websockets integration.

## Why are you building this app?

I have been having troubles implementing sockets on a nextjs base application, so I wanted to build an app that was really focus on the use of websockets, so for that reason and because it’s one of the most common examples when you want to learn to use sockets, a chat app was the perfect fit for this project.

## What will be you using for the frontend?

For the frontend part I will be using the components from shadcn, alongside with tailwind, and that pretty much everything that I will use there.

## Design of the app

When I started this project I thought that one thing that was need for this app, were users, however, how the time past and I develop the app I quite realize that the focus for this app need to be the sockets, so I will skip the users part an just focus on the socket integrations.

## Socket integration

For the socket integration I use https://socket.io/ and follow their integration guide about nextjs ( https://socket.io/how-to/use-with-nextjs) 

### Overview of the socket io integration

On [socket.io](http://socket.io) the way to integrate nextjs is to create a custom nextjs server, for that we need to create a `server.js` file and in our `package.json` call it how the entry point for the application,

just like these:

```json
{
  "scripts": {
+   "dev": "node server.js",
+   "start": "NODE_ENV=production node server.js"
  }
}
```

I personal like to have a separete command on dev for test sockets so instead of using `dev` I use `dev:socket` 

Depending if we use app router or pages on our nextjs app, we will need to add some lines to the file `socket.js` in the client part, we then use a `useEffect` and start with the connection to the socket. But I will skip this to start talking about the changes that I did to the integration to work better with them.

### My personal adaptations to the integration

First of all I create a `provider` for sharing the instance of the socket into the app. So in a folder for all my providers, I write a `socket.provider.tsx` file, that looks like these:

```tsx
"use client"
import { socket } from "@/socket"
import { createContext, useContext, useEffect, useState } from "react"

export const SocketContext = createContext<typeof socket | null>(null)

export function SocketProvider({ children }: { children: React.ReactNode }) {
	const [isConnected, setIsConnected] = useState(false)
	const [transport, setTransport] = useState("N/A")

	useEffect(() => {
		if (socket.connected) {
			onConnect()
		}

		function onConnect() {
			setIsConnected(true)
			setTransport(socket.io.engine.transport.name)
			console.log(socket)
			socket.io.engine.on("upgrade", (transport: any) => {
				setTransport(transport.name)
			})
		}

		function onDisconnect() {
			setIsConnected(false)
			setTransport("N/A")
		}

		socket.on("connect", onConnect)
		socket.on("disconnect", onDisconnect)

		return () => {
			socket.off("connect", onConnect)
			socket.off("disconnect", onDisconnect)
		}
	}, [])

	return (
		<SocketContext.Provider value={socket}>{children}</SocketContext.Provider>
	)
}

export function useSocket(event?: string, callback?: (data: any) => void) {
	const socket = useContext(SocketContext)

	useEffect(() => {
		if (event && callback && socket) {
			socket?.on(event, callback)
		}

		return () => {
			socket?.off(event, callback)
		}
	}, [callback, event, socket])

	return socket
}
```

We create a context called `SocketContext` inside the `SocketProvider` we add the code that socket io shows for creating a socket connection and pass the instance of the socket to the value of the provider. Finally we have a `hook` for adding a new event and a callback for that specific event.

In our app we will have something like these:

```tsx
useSocket(ChatEvent.Send, data => {
	setCurrentMessages([...getCurrentMessages(), { id: 0, msg: data, user: 1 }])
})
```

And in the `server.js` file something like these:

```tsx
io.on("connection", socket => {
	socket.on(ChatEvent.Send, data => {
		onSendChatEvent(socket, data)
	})
})
```
## Final words

I know that this post was more focus on sharing about the integration of socket on nextjs, but that also the reason that I started the project in first place, so I didn’t find a justification to share how the rest of the app was build, so yeah, that was pretty much everything that I wanted to talk about, in the future I will start integrating sockets for my applications.