跳至主要內容

如何在 Next.js 中使用

本指南說明如何在 Next.js 應用程式中使用 Socket.IO。

伺服器

Socket.IO 伺服器可以與 Next.js 共用相同的底層 HTTP 伺服器。您只需在專案的根目錄建立一個 server.js 檔案

server.js
import { createServer } from "node:http";
import next from "next";
import { Server } from "socket.io";

const dev = process.env.NODE_ENV !== "production";
const hostname = "localhost";
const port = 3000;
// when using middleware `hostname` and `port` must be provided below
const app = next({ dev, hostname, port });
const handler = app.getRequestHandler();

app.prepare().then(() => {
const httpServer = createServer(handler);

const io = new Server(httpServer);

io.on("connection", (socket) => {
// ...
});

httpServer
.once("error", (err) => {
console.error(err);
process.exit(1);
})
.listen(port, () => {
console.log(`> Ready on http://${hostname}:${port}`);
});
});

server.js 檔案會變成您的應用程式進入點

{
"scripts": {
- "dev": "next dev",
+ "dev": "node server.js",
"build": "next build",
- "start": "next start",
+ "start": "NODE_ENV=production node server.js",
"lint": "next lint"
}
}

瞧!

參考:https://nextjs.dev.org.tw/docs/pages/building-your-application/configuring/custom-server

提示

這兩種 App 路由器和 Pages 路由器都可以使用。

注意

來自 Next.js 文件

  • 在決定使用自訂伺服器之前,請記住,只有當 Next.js 的整合路由器無法滿足您的應用程式需求時,才應使用自訂伺服器。自訂伺服器將移除重要的效能最佳化,例如無伺服器函式和 自動靜態最佳化
  • 自訂伺服器無法部署在 Vercel 上。
  • 獨立輸出模式,不會追蹤自訂伺服器檔案,而且此模式會輸出一個獨立的 minimal server.js 檔案。

用戶端

在用戶端方面,我們 React 指南 中的所有提示都適用。

唯一的不同是您需要將 Socket.IO 用戶端從伺服器端渲染 (SSR) 中排除

結構

├── src
│ ├── app
│ │ └── page.js
│ └── socket.js
└── package.json
src/socket.js
"use client";

import { io } from "socket.io-client";

export const socket = io();
註解

"use client" 表示檔案是用戶端套件的一部分,不會進行伺服器端渲染。

參考:https://nextjs.dev.org.tw/docs/app/building-your-application/rendering/client-components

src/app/page.js
"use client";

import { useEffect, useState } from "react";
import { socket } from "../socket";

export default function Home() {
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);

socket.io.engine.on("upgrade", (transport) => {
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 (
<div>
<p>Status: { isConnected ? "connected" : "disconnected" }</p>
<p>Transport: { transport }</p>
</div>
);
}
註解

我們可以使用

const [isConnected, setIsConnected] = useState(socket.connected);

代替

const [isConnected, setIsConnected] = useState(false);

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

但這會觸發 Next.js 編譯器的某些警告,因為用戶端渲染的頁面可能與伺服器端渲染的輸出不符。

未捕捉的錯誤:文字內容與伺服器呈現的 HTML 不符。

在上述範例中,transport 變數是建立 Socket.IO 連線時使用的底層傳輸,可以是

如果一切順利,您應該會看到

Status: connected
Transport: websocket

然後,您可以使用以下方式在 Socket.IO 伺服器和用戶端之間交換訊息

  • socket.emit() 傳送訊息
socket.emit("hello", "world");
  • socket.on() 接收訊息
socket.on("hello", (value) => {
// ...
});

各位,謝謝閱讀!

返回範例清單