Mattar 開発日記

Next.jsだけでsocket.io通信したい

· wamo

やりたいこと

クライアント側でつぶやいた内容が、別のクライアントで即座に反映される。

socket.ioのインストール

npm i socket.io socket.io-client

レスポンスの型定義を作成

src/pages/types/socket.d.tsに作成します。

import { Server as NetServer, Socket } from "net"
import { NextApiResponse } from "next"
import { Server as SocketIOServer } from "socket.io"

export type NextApiResponseServerIO = NextApiResponse & {
  socket: Socket & {
    server: NetServer & {
      io: ServerIO
    }
  }
}

socket.io サーバー用のAPIを作成

src/pages/api/socket.tsに作成します。(これはapi内ならどこでもいい)

import { NextApiRequest, NextApiResponse } from 'next'
import { Server as NetServer, Socket } from "net"
import { Server as ServerIO } from "socket.io"
import { NextApiResponseServerIO } from "types/socket"

export default async function handler(req: NextApiRequest, res: NextApiResponseServerIO) {
  if (!res.socket.server.io) {
    console.log(`New Socket.io server...`)
    const httpServer: NetServer = res.socket.server as any
    const io = new ServerIO(httpServer, {
      path: `/api/socket`,
    })
    res.socket.server.io = io
  }
  res.end();
}

socket.io の更新用APIを作成

要はデータの更新(作成)をするときのAPIです。
src/pages/api/post.tsに作成します(これもapi内ならどこでもいい)

import type { NextApiRequest, NextApiResponse } from 'next'
import { PrismaClient } from '@prisma/client'
import { NextApiResponseServerIO } from "types/socket"
const prisma = new PrismaClient()

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponseServerIO
) {
  const { method } = req
  switch (method) {
    case 'POST':
      const post = await prisma.post.create({
        data: req.body,
      })
      res.socket.server.io.emit("message", req.body)
      res.status(200).json(post)
      break
  }
}

socket.io-clientを作成

import { useEffect } from "react";
import { io } from 'socket.io-client'
useEffect(() => {
  const socket = io("http://localhost:3000", {
    path: '/api/socket',
  })
  socket.on('connect', () => {
    console.log("SOCKET CONNECTED!", socket.id)
  })
  socket.on(`message`, (message: string) => {
    console.log(message)
  })
  if (socket) return () => socket.disconnect()
}, [])

return (
  ...
)

あとはnext devしてメッセージを送信するとちゃんとメッセージを受信するはずです。