我正在尝试使用基本的WebSocket设置:
- 客户端:Next.js 14
- 服务器:Express
- WebSockets:socket-io
以下是最重要的文件:
服务端
我的Express服务器只有一个文件,看起来像这样:
第一个月
import * as socket from "socket.io";
import express from "express";
import http from "http";
import cors from "cors";
const app = express();
app.use(cors());
const server = http.createServer(app);
const io = new socket.Server(server, {
cors: {
origin: true,
},
});
io.on("connection", async (socket) => {
console.log(`Connection established`, socket.id);
socket.on("disconnect", () => {
console.log("user disconnected", socket.id);
});
socket.on("chat-message", (text) => {
console.log(text);
socket.broadcast.emit("chat-message", text);
});
});
server.listen(4000, () => {
console.log("Server running on http://localhost:4000");
});
字符串
Client
在客户端上,我有两个相关文件:app/lib/socket.ts
个
问题是:当应用程序第一次启动时,此代码会执行两次!我在服务器上看到initialize socket
日志(即在我运行Next.js应用程序的终端中)*,在客户端上看到 *(即在浏览器控制台中)。
import { io } from 'socket.io-client';
const url = 'http://localhost:4000';
console.log(`initialize socket`);
export const socket = io(url);
型app/page.tsx
个
"use client";
import { useState, useEffect } from "react";
import { socket } from "./lib/socket";
interface Message {
text: string;
}
export default function Home() {
const [message, setMessage] = useState("");
const [messageHistory, setMessageHistory] = useState<Message[]>([
{
text: "hello",
},
{
text: "world",
},
]);
const newMessageReceived = (e) => {
console.log(`received message: `, e);
setMessageHistory((oldMessageHistory) => [...oldMessageHistory, { text: e }]);
};
useEffect(() => {
socket.on("chat-message", newMessageReceived);
return () => {
console.log(`return from useEffect`);
socket.off("chat-message", newMessageReceived);
};
}, []);
const sendMessage = async (e: any) => {
e.preventDefault();
const newMessage = message;
setMessage("");
console.log(`sendMessage`, newMessage);
socket.emit("chat-message", newMessage);
setMessageHistory((oldMessageHistory) => [...oldMessageHistory, { text: newMessage }]);
};
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
<p className="fixed left-0 top-0 flex w-full justify-center border-b border-gray-300 bg-gradient-to-b from-zinc-200 pb-6 pt-8 backdrop-blur-2xl lg:static lg:w-auto lg:rounded-xl lg:border lg:bg-gray-200 lg:p-4 lg:dark:bg-zinc-800/30">
<code className="font-mono font-bold">CoolChat 😎</code>
</p>
</div>
<div className="">
{messageHistory.map((message, i) => {
return <div key={i}>{message.text}</div>;
})}
</div>
<form
id="text-input-container"
className="bg-gray-300 py-4 px-2 w-full flex items-center justify-center"
onSubmit={sendMessage}
>
<div className="text-center bg-white w-full md:w-1/3 px-3 py-2 flex gap-3 rounded-xl drop-shadow-2xl">
<input
name="message"
value={message}
onChange={(e) => setMessage(e.target.value)}
id="message"
className="focus:outline-none px-2 flex-1 rounded-xl"
type="text"
placeholder="What do you want to say?"
/>
<button type="submit" className="rounded-xl px-3 py-2 bg-gray-600 text-gray-100 text-sm">
Send
</button>
</div>
</form>
</main>
);
}
型
下面是当我运行代码时发生的事情:
1.使用npm run dev
启动服务器
1.服务器打印Server running on http://localhost:4000
1.使用npm run dev
启动客户端
1.打开新的浏览器窗口并转到localhost:3000
1.客户端(终端)打印:initialize socket
1.客户端(浏览器)打印:initialize socket
1.服务器打印Connection established wQGEI_1USi_4T9n-AAAB
1.服务器打印Connection established 1SPz0765uUEvMQgBAAAD
1.(有时第三次):服务器打印Connection established BOAeHMUMeJ5zb2EJAAAF
1.打开第二个浏览器窗口并转到localhost:3000
1.客户端(浏览器)打印:initialize socket
1.服务器打印Connection established um8qdP-yV9btkqVAAAAH
1.打开第三个浏览器窗口并转到localhost:3000
1.客户端(浏览器)打印:initialize socket
1.服务器打印Connection established um8qdP-yV9btkqVAAAAH
因此,正如您所看到的,当我第一次连接到localhost:3000
时,套接字被初始化两次-一次是服务器,一次是客户端。
在随后的所有时间里,随着新的浏览器窗口导航到localhost:3000
,套接字只会像我预期的那样运行一次(在浏览器中,而不是在服务器上)。
- 有人能解释一下为什么代码会被执行两次,一次在客户端(我希望它发生),一次在服务器上(我不希望它发生)?这可能是显而易见的,但我是一个Next.js新手,所以我会感谢任何解释(也许是一些额外的资源链接)。
- 有人能解释一下如何防止这种情况,只在客户端运行代码来防止“双重连接”吗?
1条答案
按热度按时间p8h8hvxi1#
正如你提到的,你正在使用Next.js 14,并且在你的本地环境中面临这个问题。很可能React会渲染你的组件两次,这会导致建立多个连接。
我建议你在
next.config.js
文件中禁用reactStrictMode
。它应该会为你修复这个问题。字符串