You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Socket Context Provider在React组件中无法正常使用的问题排查

解决Socket.io客户端组件无法监听userCount事件的问题

问题原因分析

  1. 服务器端发送时机不匹配:若服务器仅在客户端首次连接时推送userCount,而组件的监听逻辑在socket连接完成后才执行(组件挂载晚于连接建立),会错过初始消息。
  2. Next.js SSR环境的实例异常:模块顶层直接创建socket实例会在服务器端执行,导致客户端复用的实例存在兼容性问题,或组件初始化时socket未完成客户端侧的连接。
  3. 缺少监听清理逻辑:虽非直接诱因,但会引发后续内存泄漏或重复监听问题。

具体解决方案

1. 修改Socket上下文,适配Next.js SSR环境

将socket实例的创建移至客户端useEffect中,避免服务器端生成无效实例:

// context/socket.tsx
import React, { createContext, useEffect, useState } from "react";
import { io, Socket } from "socket.io-client";

const SocketContext = createContext<Socket | null>(null);

const SocketProvider = ({ children }: { children: React.ReactNode }) => {
  const [socket, setSocket] = useState<Socket | null>(null);

  useEffect(() => {
    // 仅在客户端环境创建socket连接
    if (typeof window === 'undefined') return;

    const newSocket = io("http://localhost:3000", {
      reconnectionDelay: 1000,
      reconnection: true,
      reconnectionAttempts: 10,
      agent: false,
      upgrade: false,
      rejectUnauthorized: false,
    });

    newSocket.on("connect", () => {
      console.log("someone connected: ", newSocket?.id);
    });

    setSocket(newSocket);

    // 组件卸载时断开连接
    return () => {
      newSocket.disconnect();
    };
  }, []);

  return (
    <SocketContext.Provider value={socket}>{children}</SocketContext.Provider>
  );
};

export { SocketContext, SocketProvider };

2. 调整服务器端发送逻辑

确保服务器能响应客户端主动请求,并在客户端连接/断开时广播在线人数:

// 服务器端Node.js示例代码
const { Server } = require("socket.io");
const io = new Server(3000, {
  cors: { origin: "http://localhost:3000" } // 按需修改前端地址
});

io.on("connection", (socket) => {
  // 响应客户端主动请求,推送当前在线数
  socket.on("requestUserCount", () => {
    socket.emit("userCount", io.engine.clientsCount);
  });

  // 新客户端连接时,广播更新所有客户端的在线数
  io.emit("userCount", io.engine.clientsCount);

  // 客户端断开时,广播更新在线数
  socket.on("disconnect", () => {
    io.emit("userCount", io.engine.clientsCount);
  });
});

3. 优化Home组件的监听逻辑

添加主动请求逻辑确保组件挂载后获取最新数据,并清理监听避免内存泄漏:

// components/Home.tsx
import { SocketContext } from '../context/socket';
import { useAccount } from 'wagmi';
import { useState, useEffect, useContext } from 'react';
import type { NextPage } from 'next';

const Home: NextPage = () => {
  const { address } = useAccount();
  const [userCount, setUserCount] = useState(0);
  const socket = useContext(SocketContext);

  useEffect(() => {
    if (!socket) return;

    // 定义独立处理函数,方便后续移除监听
    const handleUserCount = (data: number) => {
      console.log(data);
      setUserCount(data);
    };

    // 主动向服务器请求当前在线数
    socket.emit('requestUserCount');
    // 监听userCount事件
    socket.on('userCount', handleUserCount);

    // 组件卸载时移除监听
    return () => {
      socket.off('userCount', handleUserCount);
    };
  }, [socket]); // 依赖socket实例,确保就绪后执行逻辑

  return (
    <div>
      <p>当前在线人数:{userCount}</p>
      {/* 其他组件内容 */}
    </div>
  );
};

export default Home;

内容的提问来源于stack exchange,提问作者kalculated

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 01:15:39