npm package: @gulibs/socket.io-react-hooks
Description: Type-safe Socket.IO React Hooks library with advanced features
Author: gulibs
Latest version: 0.0.3

# @gulibs/socket.io-react-hooks

类型安全的 Socket.IO React Hooks 库，提供比现有库更多的功能和更好的开发体验。

[![npm version](https://img.shields.io/npm/v/@gulibs/socket.io-react-hooks.svg)](https://www.npmjs.com/package/@gulibs/socket.io-react-hooks)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## ✨ 特性

- 🎯 **完整的 TypeScript 支持** - 完整的类型定义和类型推断
- 🚀 **13+ 个实用 Hooks** - 覆盖大多数实时通信场景
- 🔌 **自动连接管理** - 智能连接共享和清理
- 🌐 **SSR 兼容** - 支持服务端渲染
- 📦 **Tree-shakeable** - 只打包你使用的部分
- ⚡️ **轻量级** - gzipped 仅约 5KB

## 📦 安装

```bash
# npm
npm install @gulibs/socket.io-react-hooks socket.io-client

# yarn
yarn add @gulibs/socket.io-react-hooks socket.io-client

# pnpm
pnpm add @gulibs/socket.io-react-hooks socket.io-client
```

## 🧪 测试应用

本库包含一个完整的交互式测试应用，用于测试和学习所有 13 个 Hooks 的功能。

### 启动测试应用

```bash
# 1. 确保您的 Socket.IO 服务器正在运行（默认端口 7001）

# 2. 启动测试应用
yarn dev

# 3. 在浏览器中打开 http://localhost:5173
```

### 配置服务器地址

测试应用默认连接到 `http://localhost:7001`。您可以通过以下方式配置：

**环境变量**:

```bash
VITE_SOCKET_URL=http://your-server:port yarn dev
```

**应用内配置**: 在 useSocket 测试页面输入服务器地址

### 测试功能

- ✅ **13 个 Hook 的独立测试页面** - 每个 Hook 都有详细的测试界面
- ✅ **2 个综合测试场景** - 聊天室和多用户协作
- ✅ **实时状态监控** - 连接状态、延迟、在线用户等
- ✅ **交互式操作** - 通过 UI 直接测试各种功能
- ✅ **完整的使用示例** - 每个页面都包含代码示例

详细的测试说明请参考 [TESTING.md](./TESTING.md)。

## 🚀 快速开始

### 1. 添加 Provider

```tsx
import { SocketIOProvider } from '@gulibs/socket.io-react-hooks'

function App() {
  return (
    <SocketIOProvider defaultOptions={{ url: 'http://localhost:7001' }}>
      <YourComponents />
    </SocketIOProvider>
  )
}
```

**SocketIOProvider 属性：**

- `children` - React 子组件（必需）
- `defaultOptions?` - 默认 Socket.IO 客户端选项（`UseSocketOptions`，可选）
  - `url?: string` - Socket.IO 服务器 URL
  - `enabled?: boolean` - 是否启用连接，默认 `true`
  - 其他 Socket.IO 客户端选项（如 `auth`, `transports`, `reconnectionAttempts`, `path` 等）

  这些默认选项会被所有子组件中的 `useSocket` Hook 继承，子组件可以通过传递自己的选项来覆盖。

### 2. 使用 Hooks

```tsx
import { useSocket, useSocketEvent } from '@gulibs/socket.io-react-hooks'

function ChatComponent() {
  // 建立连接
  const { socket, connected } = useSocket()

  // 监听消息
  const { lastMessage, sendMessage } = useSocketEvent<string>('message')

  if (!connected) {
    return <div>连接中...</div>
  }

  return (
    <div>
      <p>最新消息: {lastMessage}</p>
      <button onClick={() => sendMessage('Hello!')}>
        发送消息
      </button>
    </div>
  )
}
```

## 📚 API 文档

### SocketIOProvider

React Context Provider，用于管理所有 Socket.IO 连接。

```tsx
<SocketIOProvider defaultOptions={options?}>
  {children}
</SocketIOProvider>
```

**属性（Props）：**

- `children` - React 子组件（必需，`React.ReactNode`）
- `defaultOptions?` - 默认 Socket.IO 客户端选项（`UseSocketOptions`，可选）
  - `url?: string` - Socket.IO 服务器 URL
    - 示例：`'http://localhost:7001'`
    - 如果为空字符串或未提供，将使用当前页面的 origin
  - `enabled?: boolean` - 是否启用连接，默认 `true`
  - 其他 Socket.IO 客户端选项（继承 `ManagerOptions` 和 `SocketOptions`）：
    - `auth?: object` - 认证信息
    - `transports?: Transport[]` - 传输方式，如 `['websocket']`
    - `reconnectionAttempts?: number` - 最大重连次数
    - `reconnectionDelay?: number` - 重连延迟（毫秒）
    - `path?: string` - Socket.IO 路径，默认 `'/socket.io'`
    - 等等。..

**说明：**

- `defaultOptions` 会被所有子组件中的 `useSocket` Hook 继承
- 子组件可以通过传递自己的选项来覆盖默认选项
- 多个组件使用相同的配置时会共享同一个 Socket 连接实例
- 完全支持 SSR，在服务端会返回安全的 mock 对象

**示例：**

```tsx
// 基础用法
<SocketIOProvider>
  <App />
</SocketIOProvider>

// 配置默认服务器地址
<SocketIOProvider defaultOptions={{ url: 'http://localhost:7001' }}>
  <App />
</SocketIOProvider>

// 配置认证和传输方式
<SocketIOProvider
  defaultOptions={{
    url: 'https://api.example.com',
    auth: { token: 'your-token' },
    transports: ['websocket'],
    reconnectionAttempts: 5
  }}
>
  <App />
</SocketIOProvider>

// 配置路径
<SocketIOProvider
  defaultOptions={{
    url: 'http://localhost:7001',
    path: '/custom-socket-path'
  }}
>
  <App />
</SocketIOProvider>
```

### 基础 Hooks

#### useSocket

管理 Socket.IO 连接。

```tsx
// 函数重载
const { socket, connected, error } = useSocket(options?)
const { socket, connected, error } = useSocket(namespace, options?)
const { socket, connected, error } = useSocket<ServerToClientEvents, ClientToServerEvents>(options?)
const { socket, connected, error } = useSocket<ServerToClientEvents, ClientToServerEvents>(namespace, options?)
```

**参数：**
- `namespace?` - Socket.IO namespace（字符串，如 `/chat`），默认 `/`
- `options?` - Socket.IO 客户端选项（继承 `ManagerOptions` 和 `SocketOptions`）
  - `url?: string` - Socket.IO 服务器 URL
  - `enabled?: boolean` - 是否启用连接，默认 `true`
  - 其他 Socket.IO 客户端选项（如 `auth`, `transports`, `reconnectionAttempts` 等）

**返回：**
- `socket` - Socket 实例（`SocketLike` 类型）
- `connected` - 连接状态（`boolean`）
- `error` - 错误信息（`Error | null`）

**示例：**

```tsx
// 基础用法
const { socket, connected } = useSocket()

// 指定 namespace
const { socket } = useSocket('/chat')

// 指定 namespace 和选项
const { socket } = useSocket('/chat', {
  auth: { token }
})

// 条件连接
const { socket } = useSocket({
  enabled: isAuthenticated,
  auth: { token }
})

// TypeScript 类型支持
interface ServerToClientEvents {
  message: (text: string) => void
}

interface ClientToServerEvents {
  sendMessage: (text: string) => void
}

const { socket } = useSocket<ServerToClientEvents, ClientToServerEvents>()
```

#### useSocketEvent

监听和发送 Socket.IO 事件，支持消息去重和序列号。

```tsx
// 函数重载
const { socket, status, error, lastMessage, sendMessage } = useSocketEvent(socket, event, options?)
const { socket, status, error, lastMessage, sendMessage } = useSocketEvent(event, options?)
```

**参数：**
- `socketOrEvent` - Socket 实例或事件名
  - 如果传入 Socket 实例，则使用该实例
  - 如果传入字符串（事件名），则自动创建 Socket 连接
- `eventOrOptions?` - 事件名或配置选项
  - 当第一个参数是 Socket 时，此参数为事件名（字符串）
  - 当第一个参数是事件名时，此参数为配置选项
- `options?` - 配置选项（当第一个参数是 Socket 时使用）
  - `onMessage?: (message: T) => void` - 收到消息时的回调函数
  - `keepPrevious?: boolean` - 组件重新挂载时是否保留上一次的消息，默认 `false`
  - `dedupe?: boolean | { enabled?: boolean, getId?: (message: T) => string | number, window?: number }` - 消息去重配置
    - `enabled?: boolean` - 是否启用去重，默认 `true`
    - `getId?: (message: T) => string | number` - 自定义消息 ID 提取函数，默认使用 `message.id` 或 `message.messageId`
    - `window?: number` - 去重时间窗口（毫秒），默认 `60000`（1 分钟）
  - `sequenceNumber?: boolean | { enabled?: boolean, fieldName?: string | string[], maxWaitTime?: number }` - 消息序列号配置
    - `enabled?: boolean` - 是否启用序列号，默认 `true`
    - `fieldName?: string | string[]` - 序列号字段名，默认 `'sequenceNumber'` 或 `'seq'` 或 `'sequence'`
    - `maxWaitTime?: number` - 最大等待时间（毫秒），默认 `5000`
  - 其他 `UseSocketOptions` 选项（如 `url`, `enabled` 等）

**返回：**
- `socket` - Socket 实例（`SocketLike` 类型）
- `status` - 连接状态（`'connecting' | 'connected' | 'disconnected'`）
- `error` - 错误信息（`Error | null`）
- `lastMessage` - 最新消息（`T | undefined`）
- `sendMessage` - 发送消息函数（`(...args: any[]) => Promise<any>`）
  - 接受任意数量的参数，最后一个参数可以是回调函数
  - 如果提供回调函数，则使用回调；否则返回 Promise
  - 支持泛型：`sendMessage<T>(...args) => Promise<T>`

**示例：**

```tsx
// 使用已有的 socket
const { socket } = useSocket()
const { lastMessage, sendMessage } = useSocketEvent(socket, 'message')

// 不传递 socket，内部自动创建
const { lastMessage, sendMessage } = useSocketEvent('message')

// 带回调
const { lastMessage } = useSocketEvent(socket, 'message', {
  onMessage: (msg) => console.log('收到消息:', msg)
})

// 启用消息去重
const { lastMessage } = useSocketEvent('message', {
  dedupe: {
    enabled: true,
    getId: (msg) => msg.id, // 自定义 ID 提取函数
    window: 60000 // 去重时间窗口（1分钟）
  }
})

// 启用消息序列号（确保消息顺序）
const { lastMessage } = useSocketEvent('message', {
  sequenceNumber: {
    enabled: true,
    fieldName: 'sequenceNumber', // 或 ['seq', 'sequence']
    maxWaitTime: 5000 // 最大等待时间（毫秒）
  }
})

// 发送带确认的消息
const response = await sendMessage<{ status: string }>('Hello')
console.log(response.status)
```

### 扩展 Hooks

#### useSocketConnection

监控连接状态。

```tsx
const { isConnected, isReconnecting, reconnectAttempts } = useSocketConnection(options?)
```

**参数：**
- `options?` - Socket.IO 客户端选项（`UseSocketOptions`）

**返回：**
- `isConnected` - 是否已连接（`boolean`）
- `isReconnecting` - 是否正在重连（`boolean`）
- `reconnectAttempts` - 重连尝试次数（`number`）

#### useSocketReconnection

高级重连控制。

```tsx
const { reconnect, disconnect, isReconnecting, reconnectAttempts, reconnectError } = useSocketReconnection(options?)
```

**参数：**
- `options?` - 重连配置选项（`UseSocketReconnectionOptions`）
  - `maxAttempts?: number` - 最大重连次数，默认 `Infinity`
  - `reconnectionDelay?: number` - 重连延迟（毫秒），默认 `1000`
  - 其他 `UseSocketOptions` 选项（如 `url`, `enabled` 等）

**返回：**
- `reconnect` - 手动重连函数（`() => void`）
- `disconnect` - 断开连接函数（`() => void`）
- `isReconnecting` - 是否正在重连（`boolean`）
- `reconnectAttempts` - 重连尝试次数（`number`）
- `reconnectError` - 重连错误（`Error | null`）

#### useSocketLatency

测量延迟。

```tsx
const { latency, averageLatency, ping } = useSocketLatency(options?)
```

**参数：**
- `options?` - 延迟测量配置选项（`UseSocketLatencyOptions`）
  - `interval?: number` - Ping 间隔（毫秒），默认 `5000`
  - 其他 `UseSocketOptions` 选项（如 `url`, `enabled` 等）

**返回：**
- `latency` - 当前延迟（毫秒，`number | null`）
- `averageLatency` - 平均延迟（毫秒，`number | null`）
- `ping` - 手动发送 ping 函数（`() => void`）

#### useSocketTyping

处理"正在输入"指示器。

```tsx
const { typingUsers, startTyping, stopTyping } = useSocketTyping(event?, options?)
```

**参数：**
- `event?` - 事件名，默认 `'typing'`
- `options?` - 配置选项（`UseSocketTypingOptions`）
  - `timeout?: number` - 超时时间（毫秒），超时后自动停止输入状态，默认 `3000`
  - 其他 `UseSocketOptions` 选项（如 `url`, `enabled` 等）

**返回：**
- `typingUsers` - 其他用户的输入状态列表（`string[]`）
- `startTyping` - 开始输入函数（`() => void`）
- `stopTyping` - 停止输入函数（`() => void`）

#### useSocketPresence

用户在线状态管理。

```tsx
const { onlineUsers, updatePresence } = useSocketPresence(options?)
```

**参数：**
- `options?` - Socket.IO 客户端选项（`UseSocketPresenceOptions`，继承 `UseSocketOptions`）

**返回：**
- `onlineUsers` - 在线用户列表（`string[]`）
- `updatePresence` - 更新当前用户的在线状态函数（`(status: 'online' | 'away' | 'offline') => void`）

**示例：**

```tsx
// 更新状态
updatePresence('online')
updatePresence('away')
updatePresence('offline')
```

#### useSocketRoom

房间管理。

```tsx
const { currentRooms, joinRoom, leaveRoom, leaveAllRooms } = useSocketRoom(options?)
```

**参数：**
- `options?` - 房间管理配置选项（`UseSocketRoomOptions`）
  - `autoLeaveOnUnmount?: boolean` - 组件卸载时是否自动离开房间，默认 `true`
  - `joinEventName?: string` - 自定义加入房间事件名，默认 `'joinRoom'`
  - `leaveEventName?: string` - 自定义离开房间事件名，默认 `'leaveRoom'`
  - 其他 `UseSocketOptions` 选项（如 `url`, `enabled` 等）

**返回：**
- `currentRooms` - 当前已加入的房间列表（`string[]`）
- `joinRoom` - 加入房间函数（`(room: string) => Promise<void>`）
- `leaveRoom` - 离开房间函数（`(room: string) => Promise<void>`）
- `leaveAllRooms` - 离开所有房间函数（`() => Promise<void>`）

**示例：**

```tsx
// 加入房间
await joinRoom('room-1')

// 离开房间
await leaveRoom('room-1')

// 离开所有房间
await leaveAllRooms()
```

#### useSocketBroadcast

广播消息。

```tsx
const { broadcast, broadcastToRoom } = useSocketBroadcast(options?)
```

**参数：**
- `options?` - Socket.IO 客户端选项（`UseSocketBroadcastOptions`，继承 `UseSocketOptions`）

**返回：**
- `broadcast` - 广播消息到所有用户（除了自己）函数（`(event: string, data: any) => void`）
- `broadcastToRoom` - 广播消息到指定房间函数（`(room: string, event: string, data: any) => void`）

**示例：**

```tsx
// 广播到所有用户
broadcast('notification', { message: 'Hello everyone!' })

// 广播到特定房间
broadcastToRoom('room-1', 'notification', { message: 'Hello room!' })
```

#### useSocketAck

带确认的消息，支持并发请求和自动重试。

```tsx
const {
  sendWithAck,
  isPending,
  ackError,
  pendingRequests,
  getRequest,
  getAllRequests
} = useSocketAck({
  timeout?: number, // Default: 5000ms
  retry?: boolean | number | {
    maxRetries?: number,        // Default: 3
    strategy?: 'fixed' | 'exponential', // Default: 'exponential'
    initialDelay?: number,       // Default: 1000ms
    maxDelay?: number           // Default: 10000ms
  }
})
```

**参数：**
- `timeout?` - 确认超时时间（毫秒），默认 5000
- `retry?` - 重试配置
  - `false`: 不重试（默认）
  - `number`: 最大重试次数
  - `object`: 详细重试配置

**返回：**
- `sendWithAck` - 发送带确认的消息函数（`<T = any>(event: string, data: any, requestId?: string) => Promise<T>`）
  - `event` - 事件名
  - `data` - 消息数据
  - `requestId?` - 可选的请求 ID，用于跟踪特定请求
  - 返回 Promise，解析为服务器响应
- `isPending` - 是否有任何请求正在等待（`boolean`）
- `ackError` - 最后一个请求的错误（`Error | null`）
- `pendingRequests` - 所有待处理的请求 ID 数组（`string[]`）
- `getRequest` - 获取特定请求的状态（`(requestId: string) => AckRequest | undefined`）
  - 返回的 `AckRequest` 包含：`requestId`, `event`, `data`, `status` (`'pending' | 'success' | 'error'`), `error?`, `startTime`, `retryCount?`
- `getAllRequests` - 获取所有请求（包括已完成的）（`() => AckRequest[]`）

**示例：**

```tsx
// 基础用法（无重试）
const { sendWithAck, isPending } = useSocketAck({
  timeout: 5000
})

// 发送单个请求
const response = await sendWithAck('request', { data: '...' })

// 发送多个并发请求
const [response1, response2] = await Promise.all([
  sendWithAck('request1', { data: '...' }, 'req-1'),
  sendWithAck('request2', { data: '...' }, 'req-2')
])

// 启用重试（固定延迟）
const { sendWithAck } = useSocketAck({
  timeout: 5000,
  retry: {
    maxRetries: 3,
    strategy: 'fixed',
    initialDelay: 1000
  }
})

// 启用重试（指数退避）
const { sendWithAck } = useSocketAck({
  timeout: 5000,
  retry: {
    maxRetries: 5,
    strategy: 'exponential',
    initialDelay: 1000,
    maxDelay: 10000
  }
})

// 简化重试配置（仅指定重试次数）
const { sendWithAck } = useSocketAck({
  retry: 3 // 最多重试 3 次，使用默认指数退避策略
})

// 查看所有待处理的请求
console.log(pendingRequests) // ['req-1', 'req-2']

// 获取特定请求的状态
const request = getRequest('req-1')
console.log(request?.status) // 'pending' | 'success' | 'error'
console.log(request?.retryCount) // 重试次数

// 获取所有请求（包括已完成的）
const allRequests = getAllRequests()
allRequests.forEach(req => {
  console.log(`${req.requestId}: ${req.status} (retries: ${req.retryCount || 0})`)
})
```

#### useSocketQueue

离线消息队列，支持持久化存储（localStorage/IndexedDB）。

```tsx
const { send, queueSize, clearQueue, getQueue } = useSocketQueue({
  maxSize?: number,              // Default: 100
  persistence?: 'none' | 'localStorage' | 'indexedDB' | 'auto', // Default: 'none'
  persistenceKey?: string        // Default: 'socket.io-queue-'
})
```

**参数：**
- `maxSize?` - 队列最大大小，默认 100
- `persistence?` - 持久化类型
  - `'none'`: 不持久化（仅内存，页面刷新后丢失）
  - `'localStorage'`: 使用 localStorage（适合小数据量，5-10MB）
  - `'indexedDB'`: 使用 IndexedDB（适合大数据量，性能更好）
  - `'auto'`: 自动选择（优先 IndexedDB）
- `persistenceKey?` - 持久化存储键名前缀，默认 `'socket.io-queue-'`

**返回：**
- `send` - 发送消息函数（`(event: string, data: any) => void`）
  - 在线时立即发送，离线时自动加入队列
  - `event` - 事件名
  - `data` - 消息数据
- `queueSize` - 当前队列大小（`number`）
- `clearQueue` - 清空队列函数（`() => Promise<void>`），同时清除持久化存储
- `getQueue` - 获取队列内容（`() => QueuedMessage[]`）
  - 返回的 `QueuedMessage` 包含：`event`, `data`, `timestamp`

**示例：**

```tsx
// 基础用法（无持久化）
const { send, queueSize } = useSocketQueue({
  maxSize: 100
})

// 使用 localStorage 持久化
const { send, queueSize, clearQueue, getQueue } = useSocketQueue({
  maxSize: 50,
  persistence: 'localStorage',
  persistenceKey: 'my-app-queue-'
})

// 使用 IndexedDB 持久化（推荐）
const { send, queueSize } = useSocketQueue({
  maxSize: 1000,
  persistence: 'indexedDB'
})

// 自动选择持久化类型
const { send, queueSize } = useSocketQueue({
  persistence: 'auto' // 优先使用 IndexedDB，不支持时降级到 localStorage
})

// 发送消息（离线时自动加入队列）
send('message', { text: 'Hello' })

// 页面刷新后，队列会自动从持久化存储恢复
// 连接恢复后，队列中的消息会自动发送

// 获取队列内容
const queue = getQueue()
console.log('队列中的消息:', queue)

// 清空队列（同时清除持久化存储）
clearQueue()
```

**持久化说明：**
- 启用持久化后，队列会在每次更新时自动保存
- 页面刷新后，队列会自动从持久化存储恢复
- 连接恢复后，队列中的所有消息会自动发送
- 消息发送成功后，队列和持久化存储会自动清空

#### useSocketError

统一错误处理，支持错误历史上限和自动清理。

```tsx
const { errors, lastError, clearErrors } = useSocketError({
  maxErrors?: number  // Default: 50
})
```

**参数：**
- `options?` - 错误处理配置选项（`UseSocketErrorOptions`）
  - `maxErrors?: number` - 最大错误数，默认 `50`。超过后自动移除最旧的错误
  - 其他 `UseSocketOptions` 选项（如 `url`, `enabled` 等）

**返回：**
- `errors` - 错误历史数组（`SocketErrorData[]`，按时间倒序）
  - `SocketErrorData` 包含：`code` (string), `message` (string), `detail?` (any), `timestamp` (number)
- `lastError` - 最后一个错误（`SocketErrorData | null`）
- `clearErrors` - 清除所有错误函数（`() => void`）

**示例：**

```tsx
// 基础用法（默认最多保存 50 个错误）
const { errors, lastError, clearErrors } = useSocketError()

// 自定义错误历史上限
const { errors, lastError } = useSocketError({
  maxErrors: 100 // 最多保存 100 个错误
})

// 显示错误提示
{lastError && (
  <Alert type="error">
    {lastError.message} (Code: {lastError.code})
  </Alert>
)}

// 显示错误列表
{errors.map((error, i) => (
  <div key={i}>
    {new Date(error.timestamp).toLocaleString()}: {error.message}
  </div>
))}

// 清除所有错误
<button onClick={clearErrors}>清除错误</button>
```

#### useSocketMiddleware

中间件支持，包括速率限制。

```tsx
import { useSocketMiddleware, createRateLimitMiddleware } from '@gulibs/socket.io-react-hooks'

const { emit, addMiddleware, removeMiddleware } = useSocketMiddleware(options?)
```

**参数：**
- `options?` - 中间件配置选项（`UseSocketMiddlewareOptions`）
  - `middlewares?: SocketMiddleware[]` - 初始中间件列表
  - 其他 `UseSocketOptions` 选项（如 `url`, `enabled` 等）

**返回：**
- `emit` - 通过中间件链发送消息函数（`(event: string, data: any) => void`）
- `addMiddleware` - 添加中间件函数（`(middleware: SocketMiddleware) => void`）
- `removeMiddleware` - 移除中间件函数（`(middleware: SocketMiddleware) => void`）

**中间件类型：**

```tsx
type SocketMiddleware = (
  event: string,
  data: any,
  next: (event: string, data: any) => void
) => void
```

**示例：**

```tsx
// 添加日志中间件
addMiddleware((event, data, next) => {
  console.log('发送:', event, data)
  next(event, data)
})

// 添加速率限制中间件
const rateLimitMiddleware = createRateLimitMiddleware({
  max: 10, // 最多 10 条
  window: 60000, // 1 分钟
  key: (event, data) => event, // 基于事件名限流
  onExceeded: (event, data, remaining, resetTime) => {
    console.warn(`Rate limit exceeded for ${event}. Remaining: ${remaining}`)
  }
})
addMiddleware(rateLimitMiddleware)

// 发送消息
emit('message', { text: 'Hello' })
```

## 🔧 TypeScript 支持

完整的类型定义和类型推断：

```tsx
import { useSocket, useSocketEvent } from '@gulibs/socket.io-react-hooks'

// 定义事件类型
interface ServerToClientEvents {
  message: (data: { id: string; text: string }) => void
  notification: (text: string) => void
}

interface ClientToServerEvents {
  sendMessage: (text: string, callback: (id: string) => void) => void
  joinRoom: (room: string) => void
}

// 使用类型
const { socket } = useSocket<ServerToClientEvents, ClientToServerEvents>()

// 自动类型推断
socket.on('message', (data) => {
  // data 的类型自动推断为 { id: string; text: string }
  console.log(data.text)
})

socket.emit('sendMessage', 'Hello', (id) => {
  // id 的类型自动推断为 string
  console.log(id)
})
```

## 🌟 高级用法

### 认证连接

```tsx
const useAuthenticatedSocket = (namespace?: string) => {
  const [accessToken] = useCookie('jwt')

  return useSocket(namespace, {
    enabled: !!accessToken,
    auth: { token: accessToken }
  })
}
```

### 条件连接

```tsx
const { socket, connected } = useSocket({
  enabled: user?.isAuthenticated,
  transports: ['websocket'],
  reconnectionAttempts: 5
})
```

### 自定义事件处理

```tsx
const [messages, setMessages] = useState([])

const { lastMessage } = useSocketEvent('message', {
  onMessage: (msg) => {
    setMessages(prev => [...prev, msg])
  },
  keepPrevious: true
})
```

## 🎯 服务器端渲染 (SSR)

库完全兼容 SSR，所有 Hook 在服务端都会返回安全的 mock 对象：

```tsx
// 在服务端不会创建真实连接
const { socket, connected } = useSocket()

// connected 在服务端始终为 false
// socket 返回一个 mock 对象，所有方法都是安全的 no-op

// 所有 Hook 都支持 SSR
const { lastMessage } = useSocketEvent('message') // 服务端安全
const { send } = useSocketQueue() // 服务端安全
const { sendWithAck } = useSocketAck() // 服务端安全
```

**SSR 最佳实践：**
1. 所有 Hook 在 SSR 环境下自动使用 mock，不会报错
2. 在开发环境下会显示警告信息（可通过环境变量关闭）
3. 客户端 hydration 后自动建立真实连接
4. 不需要任何特殊配置，开箱即用

## 🤝 贡献

欢迎贡献！请查看我们的 [贡献指南](CONTRIBUTING.md)。

## 📄 许可

MIT © [gulibs](https://github.com/gulibs)

## 🔗 相关链接

- [Socket.IO 官方文档](https://socket.io/docs/v4/)
- [GitHub 仓库](https://github.com/gulibs/socket.io-react-hooks)
- [问题反馈](https://github.com/gulibs/socket.io-react-hooks/issues)

## 📝 更新日志

查看 [CHANGELOG.md](CHANGELOG.md) 了解版本历史。