【开箱即用】React中使用WebSocket进行实时通讯,TS封装一个简易WebSocket

3,649 阅读3分钟

本篇文章讲前端向基于React框架以及TypeScript进行websocket的封装,例子可以直接使用。

由于业务中需要开发一个类似客服回复的实时通讯,所以用了最基本的WebSocket,如果是node做后端服务,可以使用socket.io框架,它提供了很多高级连接的方法,这是他的文档socket.io/zh-CN/docs/…

一张图简单看下ws和request的区别

image.png

通过图相信大家很清晰就能看出区别所在,接下来上代码

1.封装WebSocket

首先在项目中新建一个WebSocket的ts文件,加入以下代码,代码可以直接使用,无需改动 这是我写的一个Hook,大家可以借鉴一下,十分清晰,代码中有写明注释

import { useEffect, useRef, useState } from 'react';

//消息类型,下面的代码我用any类型,不建议用any,大家可以自己声明Message类型,为了方便我暂时用any 不用Message

type Message = {
  type: string;
  data: any;
};

type WebSocketOptions = {
  url: string;
  onOpen?: () => void;
  onClose?: (event: Event) => void;
  onError?: (event: Event) => void;
  onMessage?: (message: any) => void;
  reconnectInterval?: number;
  reconnectAttempts?: number;
};

const defaultOptions: Required<WebSocketOptions> = {
  url: '',//连接的长链接
  onOpen: () => {},//开启连接
  onClose: () => {},//关闭链接
  onError: () => {},//异常
  onMessage: () => {},//消息
  reconnectInterval: 1000,//重连时长设置
  reconnectAttempts: Number.MAX_VALUE,//最大连接范围数
};

const useWebSocket = (
  options: WebSocketOptions,
): [WebSocket | undefined, (message: any) => void, string, boolean] => {
  const { url, onOpen, onClose, onError, onMessage, reconnectInterval, reconnectAttempts } = {
    ...defaultOptions,
    ...options,
  };

  const [isConnected, setIsConnected] = useState(false);//是否连接
  const [reconnectCount, setReconnectCount] = useState(0);//用于判断重连
  const [lastMessage, setLastMessage] = useState('');//最新的消息

  const socketRef = useRef<WebSocket>();
  const reconnectTimerRef = useRef<NodeJS.Timer>();

  const connect = () => {
    //连接函数封装
    setIsConnected(false);

    const socket = new WebSocket(url);
    socket.onopen = () => {
    //开始连接
      console.log('WebSocket is connected');
      setIsConnected(true);
      setReconnectCount(0);
      onOpen();
    };
    socket.onclose = (event) => {
    //连接关闭
      console.error(`WebSocket closed with code ${event.code}`);
      setIsConnected(false);
      onClose(event);
      if (reconnectCount < reconnectAttempts) {
      //用于判断断开连接后重新连接
        reconnectTimerRef.current = setTimeout(() => {
          setReconnectCount((prevCount) => prevCount + 1);
          connect();
        }, reconnectInterval);
      }
    };
    socket.onerror = (event) => {
    //异常问题
      console.error('WebSocket error:', event);
      onClose(event);
    };
    socket.onmessage = (event) => {
    //接收到消息
      const message: any = JSON.parse(event.data);
      console.log(`WebSocket received message: ${message}`);
      setLastMessage(event.data);
      onMessage(message);
    };

    socketRef.current = socket;
  };

  useEffect(() => {
    connect();
    return () => {
      socketRef.current?.close();
      clearTimeout(reconnectTimerRef.current);
    };
  }, []);

  const sendMessage = (message: any) => {
  //用于发送消息
    if (isConnected && socketRef.current) {
      console.log(`WebSocket sending message: ${JSON.stringify(message)}`);
      socketRef.current.send(JSON.stringify(message));
    } else {
      console.error('Cannot send message - WebSocket is not connected');
    }
  };
    //暴露出我们需要的
  return [socketRef.current, sendMessage, lastMessage, isConnected];
};

export default useWebSocket;

2. 在项目中引入

//我是放在hooks文件夹下
import useWebSocket from '@/hooks/websocket';

.....
.....

//注意https的url下需要使用 wss ,http是需要使用 ws 
  const [webSocket, sendMessage, lastMessage, isConnected] = useWebSocket({
    url: 'wss://xxxxxxxxxxxxxxx',  //这里放长链接
    onOpen: () => {
    //连接成功
      console.log('WebSocket connected');
    },
    onClose: () => {
    //连接关闭
      console.log('WebSocket disconnected');
    },
    onError: (event) => {
    //连接异常
      console.error('WebSocket error:', event);
    },
    onMessage: (message) => {
    //收到消息
      console.log('WebSocket received message:', message);
    },
  });
  
.....
.....

3. 使用方法和说明

  1. 发送消息是用sendMessage
//和后端约定好消息发送格式,一般需要登陆的话可以先发送一个用户登陆的消息,用作标识
sendMessage({}); 
  1. 最新消息可以直接在lastMessage中拿到
  2. isConnected用于判断是否连接
  3. webSocket是暴露出来的整体,你可以我们封装下的所有方法

注:正常来说需要一个心跳来保持,这个需要和后端进行沟通,前端需要隔多少秒发送一个ping,来检测连接是否正常,否则立马重连

以上就是WebSocket的基本内容,满足大致需求,如果有更好的建议,欢迎指出探讨,如果是需要开速实现一个简易的WebSocket可以借鉴