如何防止socket-io在React/Next.js中示例化两个套接字(目前在服务器 * 和客户端上示例化)

vlju58qv  于 12个月前  发布在  React
关注(0)|答案(1)|浏览(85)

我正在尝试使用基本的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新手,所以我会感谢任何解释(也许是一些额外的资源链接)。
  • 有人能解释一下如何防止这种情况,只在客户端运行代码来防止“双重连接”吗?
p8h8hvxi

p8h8hvxi1#

正如你提到的,你正在使用Next.js 14,并且在你的本地环境中面临这个问题。很可能React会渲染你的组件两次,这会导致建立多个连接。
我建议你在next.config.js文件中禁用reactStrictMode。它应该会为你修复这个问题。

// next.config.js
module.exports = {
  reactStrictMode: false,
}

字符串

相关问题