useWebSocket.ts 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. "use client";
  2. import { useEffect, useRef } from "react";
  3. import { WSClient, WSMessage } from "@/lib/websocket";
  4. interface UseWebSocketOptions<T> {
  5. conversationId: number | null;
  6. enabled?: boolean;
  7. isVisitor?: boolean; // 是否是访客(默认为 true)
  8. agentId?: number; // 客服ID(如果是客服连接,需要传递)
  9. wsToken?: string; // 客服 WS 令牌(登录后下发)
  10. onMessage: (payload: WSMessage<T>) => void;
  11. onError?: (error: Event) => void;
  12. onClose?: () => void;
  13. }
  14. export function useWebSocket<T>({
  15. conversationId,
  16. enabled = true,
  17. isVisitor = true, // 默认是访客
  18. agentId,
  19. wsToken,
  20. onMessage,
  21. onError,
  22. onClose,
  23. }: UseWebSocketOptions<T>) {
  24. // 使用 useRef 存储最新的回调函数,避免因回调函数变化导致重新连接
  25. const onMessageRef = useRef(onMessage);
  26. const onErrorRef = useRef(onError);
  27. const onCloseRef = useRef(onClose);
  28. // 更新 ref 的值
  29. useEffect(() => {
  30. onMessageRef.current = onMessage;
  31. onErrorRef.current = onError;
  32. onCloseRef.current = onClose;
  33. }, [onMessage, onError, onClose]);
  34. useEffect(() => {
  35. if (!conversationId || !enabled) {
  36. return;
  37. }
  38. const client = new WSClient<T>({
  39. conversationId,
  40. isVisitor,
  41. agentId,
  42. wsToken,
  43. // 使用 ref 的 current 值,这样即使回调函数变化也不会导致重新连接
  44. onMessage: (payload) => onMessageRef.current(payload),
  45. onError: onErrorRef.current
  46. ? (error) => onErrorRef.current?.(error)
  47. : undefined,
  48. onClose: onCloseRef.current ? () => onCloseRef.current?.() : undefined,
  49. });
  50. client.connect();
  51. return () => {
  52. client.disconnect();
  53. };
  54. // 只依赖 conversationId、enabled、isVisitor 和 agentId,不依赖回调函数
  55. // 回调函数通过 useRef 存储,不会导致重新连接
  56. }, [conversationId, enabled, isVisitor, agentId, wsToken]);
  57. }