DEV Community

Carlos Estrada
Carlos Estrada

Posted on

Creating a nextjs chat app for learning to integrate sockets

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 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:

{
  "scripts": {
+   "dev": "node server.js",
+   "start": "NODE_ENV=production node server.js"
  }
}
Enter fullscreen mode Exit fullscreen mode

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:

"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
}
Enter fullscreen mode Exit fullscreen mode

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:

useSocket(ChatEvent.Send, data => {
    setCurrentMessages([...getCurrentMessages(), { id: 0, msg: data, user: 1 }])
})
Enter fullscreen mode Exit fullscreen mode

And in the server.js file something like these:

io.on("connection", socket => {
    socket.on(ChatEvent.Send, data => {
        onSendChatEvent(socket, data)
    })
})
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)