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

如何为React Context管理的Socket.io设置TS类型与初始值

React Context + Socket.io 类型修正与最佳实践

核心问题解决方案

1. 正确设置Context的TypeScript类型与默认值

首先从socket.io-client导入Socket类型,明确Context的value结构(与Provider传递的对象一致),同时考虑socket初始可能为null的情况。给createContext设置的默认值必须严格匹配类型,避免TypeScript报错。

2. 修正useState的类型声明

初始状态socket为null,因此需要将其类型指定为Socket<ServerToClientEvents, ClientToServerEvents> | null,让TypeScript明确它的可能取值范围。


修正后的完整代码

import { createContext, useContext, useEffect, useState } from "react";
import { io, Socket } from "socket.io-client"; // 导入Socket类型
import { AuthContext } from "./AuthContext";

type SocketData = {
  id: string;
  text: string;
  userId: string;
  chatId: string;
  createdAt: string;
};

interface ServerToClientEvents {
  getMessage: (data: SocketData) => void;
}

interface ClientToServerEvents {
  sendMessage: (data: { receiverId: string; data: SocketData }) => void;
  newUser: (id: string) => void;
}

// 定义Context的类型结构:包含socket字段,socket可能为null
type SocketContextType = {
  socket: Socket<ServerToClientEvents, ClientToServerEvents> | null;
};

// 设置默认值,严格匹配SocketContextType类型
export const SocketContext = createContext<SocketContextType>({ socket: null });

export const SocketContextProvider = ({
  children,
}: { children: React.ReactNode }) => {
  const { currentUser } = useContext(AuthContext);
  // 显式声明useState的类型:Socket实例或null
  const [socket, setSocket] = useState<Socket<ServerToClientEvents, ClientToServerEvents> | null>(null);

  useEffect(() => {
    // 仅在无socket实例时创建连接
    if (!socket) {
      const newSocket = io("http://localhost:4000");
      setSocket(newSocket);

      // 组件卸载时断开socket连接,避免内存泄漏
      return () => {
        newSocket.disconnect();
      };
    }
  }, [socket]);

  useEffect(() => {
    // 确保socket与currentUser都存在时再发送事件
    if (currentUser && socket) {
      socket.emit("newUser", currentUser.id);
    }

    // 用户登出(currentUser变为null)时,清理相关监听
    return () => {
      socket?.off("newUser");
    };
  }, [currentUser, socket]);

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

关键改动说明

  • 导入Socket类型:从socket.io-client引入Socket,才能正确定义上下文与状态的类型。
  • Context类型对齐:创建SocketContextType接口明确上下文结构,默认值设为{ socket: null },完全匹配类型要求。
  • 状态类型声明:显式指定useState的类型为Socket<...> | null,解决类型推导错误。
  • 内存泄漏防护:在创建socket的useEffect中添加断开连接的清理函数,组件卸载时自动释放资源;在用户状态变化的useEffect中添加事件监听清理逻辑,适配登出场景。
  • 空值安全处理:发送socket.emit前增加双重判断,避免空值调用报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:43:10