使用Socket IO client+React TS+Context API出现exports只读属性报错
错误原因
该错误是socket.io-client版本与项目ES模块编译规范不兼容导致的。当前主流React脚手架默认启用ES模块严格模式,部分版本的socket.io-client内部使用CommonJS的module.exports语法,在ES模块环境下exports是只读属性,赋值就会触发该报错。
解决方案
方案1:降级socket.io-client到兼容版本
直接安装经过验证的稳定兼容版本即可快速解决问题,执行对应包管理器命令:
- npm:
npm install socket.io-client@4.5.4 - pnpm:
pnpm add socket.io-client@4.5.4 - yarn:
yarn add socket.io-client@4.5.4
方案2:修改打包适配配置(不想降级时使用)
若项目使用Vite构建
在vite.config.ts中添加依赖预构建配置:
import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], optimizeDeps: { include: ['socket.io-client'] } })
若项目使用Create React App构建
- 安装
react-app-rewired和customize-cra - 根目录新增
config-overrides.js,添加以下配置:
const { override, addBabelInclude } = require('customize-cra'); const path = require('path'); module.exports = override( addBabelInclude([ path.resolve('src'), path.resolve('node_modules/socket.io-client') ]) );
- 修改package.json中的scripts命令,将
react-scripts替换为react-app-rewired
Socket实例初始化优化建议
你当前的代码在模块顶层直接初始化socket实例,会导致页面加载时立刻建立socket连接,且开发环境热更新时会重复创建连接,建议将初始化逻辑放到SocketProvider内部,优化后的完整实现如下:
import { createContext, useContext, useMemo, useEffect, ReactNode } from 'react'; import { io, Socket } from 'socket.io-client'; interface SocketContextType { socket: Socket; } const SocketContext = createContext<SocketContextType | undefined>(undefined); interface SocketProviderProps { children: ReactNode; } export function SocketProvider({ children }: SocketProviderProps) { // 仅在组件首次渲染时初始化socket实例 const socket = useMemo(() => io("http://localhost:5000"), []); // 组件卸载时自动断开socket连接,避免内存泄漏 useEffect(() => { return () => { socket.disconnect(); }; }, [socket]); return ( <SocketContext.Provider value={{ socket }}> {children} </SocketContext.Provider> ); } // 封装自定义调用hook,自带类型提示 export function useSocket() { const context = useContext(SocketContext); if (!context) { throw new Error("useSocket必须在SocketProvider内部使用"); } return context; }
内容的提问来源于stack exchange,提问作者dl1
相关产品推荐
相关产品推荐

