React hook实现简单的websocket封装方式

Vanna ·
更新时间:2024-11-10
· 1985 次阅读

目录

React hook实现websocket封装

react自定义hook解决websocket连接,useWebSocket

1、描述

2、代码

React hook实现websocket封装

新建websocket.ts文件

import {useState, useRef, useEffect} from 'react' const useWebsocket = ({ url:string, verify }) => {     const ws = useRef<WebSocket | null>(null)     // socket 数据     const [wsData, setMessage] = useState({})     //  socket 状态     const [readyState, setReadyState] = useState<any>({ key: 0, value: '正在连接中' })     const creatWebSocket = () => {         const stateArr = [             {key: 0, value: '正在连接中'},             {key: 1, value: '已经连接并且可以通讯'},             {key: 2, value: '连接正在关闭'},             {key: 3, value: '连接已关闭或者没有连接成功'},         ]         try {             ws.current = new WebSocket(url)             ws.current.onopen = () => {                 setReadyState(stateArr[ws.current?.readyState ?? 0])             }             ws.current.onclose = () => {                 setReadyState(stateArr[ws.current?.readyState ?? 0])             }             ws.current.onerror = () => {                 setReadyState(stateArr[ws.current?.readyState ?? 0])             }             ws.current.onmessage = (e) => {                 setMessage({...JSON.parse(e.data)})             }         } catch (error) {             console.log(error)         }     }     const webSocketInit = () => {         if (!ws.current || ws.current.readyState === 3) {             creatWebSocket()         }     }     //  关闭 WebSocket     const closeWebSocket = () => {         ws.current?.close()     }     // 发送数据     const sendMessage = (str:string) => {         ws.current?.send(str)     }     //重连     const reconnect = () => {         try {             closeWebSocket()             ws.current = null             creatWebSocket()         } catch (e) {             console.log(e)         }     }     useEffect(() => {         verify && webSocketInit()         return () => {             ws.current?.close()         }     }, [ws,verify])     return {         wsData,         readyState,         closeWebSocket,         reconnect,         sendMessage,     } } export default useWebsocket

这里一共暴露出四个参数。分别是

wsData(获得的 socket 数据)

readyState(当前 socket 状态)

closeWebSocket (关闭 socket)

reconnect(重连)

通过这几个简单的参数能够覆盖一般场景的需要。其中 verify 参数是控制是否有权限进行请求。可以根据 实际需求进行删除或新增。

重连啥的通过监听 readyState 状态进行相应操作。

下面代码为使用方法:

import React, { useState, useEffect } from 'react' import useWebsocket from '../../tools/webSocket' export default function () {     const [isLocalPage, setIsLocalPage] = useState(true)     const { wsData, readyState, closeWebSocket, reconnect } = useWebsocket({         url: 'ws://ip:端口', // 此参数为websocket地址         verify // 此参数控制是否有权限,请求该方法       })     useEffect(() => {         // 不在白名单人员之间不执行后续操作,不需要可以删除         if (!verify) {               return         }         // 接受到socket数据, 进行业务逻辑处理         if (Object.keys(wsData).length !== 0) {             console.log(wsData)         }         // 如果是已关闭且是当前页面自动重连         if (readyState.key === 3 && isLocalPage) {           reconnect()         }         // 不是当前页面 清空 webSocket 此处为优化代码使用的,不需要可以直接删除。         if (!isLocalPage) {           closeWebSocket()         }       }, [wsData, readyState, isLocalPage, verify])   }

对于 isLocalPage 感兴趣可以看下面代码是判断用户是否在当前页面。 此方法可以放在useEffect。

/*  ** 判断用户是否离开当前页面,离开后不请求轮询接口,回到当前页面重新执行轮询  */ useEffect(() => {       document.addEventListener('visibilitychange', function () {           // 页面变为不可见时触发           if (document.visibilityState === 'hidden') {               setIsLocalPage(false)           }           // 页面变为可见时触发           if (document.visibilityState === 'visible') {               setIsLocalPage(true)           }       })   })

最后,在这个代码中没有涉及到的场景就是 心跳机制,一般简单的需求可以不考虑,这块逻辑实现上也比较简单,这里就不多加阐述了。 

react自定义hook解决websocket连接,useWebSocket

react自定义hook,useWebSocket

1、描述

本来项目的告警和消息提醒是用的接口30秒调用一次,这次要改成webSocket传输。

因为前端是用的https,后端用的http,后端的socket只支持ws不支持wss,这里使用了webpack-dev-server的proxy代理了一下。

target:ws目标地址、pathRewrite:地址重写,这里是把/aapp_socket重写成aapp/websocket,ws:是否开启socket,secure: 默认情况下不接收转发到https的服务器上,如果希望支持,可以设置为false ,changeOrigin:是否跨域。差不多就这个意思

  '/aapp_socket': {                 target: `ws://xxx.xxx.xxx/`,                 pathRewrite: {                     '^/aapp_socket': 'aapp/websocket',                 },                 ws: true,                 secure: false,                 changeOrigin: true,             },

使用连接的地址:

`wss://localhost:3000/aapp_socket`;

实际的访问的地址就是:

`ws://xxx.xxx.xxx/aapp/websocket 2、代码

这里socket,没有配置心跳监测,还是通过我主动去推送来获取信息。这里是获取告警数和消息数量,

首先绑定websocket的事件。主要就是在message的事件中,连接成功后端返回的是sucess,就不做操作。后面就是判断返回的消息格式是否正确,如果不正确就重新连接。

还可以把获取消息的时间间隔,和重新连接间隔,地址等变量抽出来,作为参数传进来。

import {useCallback, useRef, useState, useEffect} from 'react'; const token = window.localStorage.getItem('authorization'); const userId = JSON.parse(window.localStorage.getItem('userInfo') || '')?.id; // 获取告警数量 const UNREAD_WARN_COUNT = 'UNREAD_WARN_COUNT'; // 获取消息数量 const UNREAD_MSG_COUNT = 'UNREAD_MSG_COUNT'; // 获取消息的间隔 const INT_TIME = 5000; // websocket状态 const webSocketStatus = {     CONNECTING: 0,     OPEN: 1,     CLOSING: 2,     CLOSED: 3, }; const useWebSocket = () => {     const [reset, setReset] = useState<boolean>(false);     const socket = useRef<WebSocket>();     const sendCount = useRef<number>(1);     const [alarmCount, setAlarmCount] = useState<number>(0);     const [messageCount, setMessageCount] = useState<number>(0);     // 开启事件,主动获取数据     const socketOnOpen = useCallback(() => {         // 判断连接状态是不是open         if (socket?.current?.readyState === webSocketStatus.OPEN) {             // 第一次加载触发一次             socket?.current?.send(JSON.stringify({businessKey: [UNREAD_MSG_COUNT, UNREAD_WARN_COUNT]}));         }         const timer = setInterval(() => {             if (socket?.current?.readyState === webSocketStatus.OPEN) {                 socket?.current?.send(JSON.stringify({businessKey: [UNREAD_MSG_COUNT, UNREAD_WARN_COUNT]}));             }         }, INT_TIME);         // 返回信息出错清除定时器         if (sendCount.current === 0) {             clearInterval(timer);             setReset(true);         }     }, [sendCount]);     // 关闭事件重新连接     const socketOnClose = useCallback(() => {         setReset(true);     }, []);     // 出错事件     const socketOnError = useCallback((err: any) => {         console.log('err: ', err);     }, []);     // 收发信息     const socketOnMessage = useCallback(         (e: any) => {             if (e.data === 'success') return;             const alarmCountObj = JSON.parse(e.data);             const paramNameArr = Object.keys(alarmCountObj);             // 判断返回告警保持连接否则断开连接             if (paramNameArr[1] === 'UNREAD_WARN_COUNT') {                 sendCount.current += 1;                 setAlarmCount(alarmCountObj.UNREAD_WARN_COUNT);                 setMessageCount(alarmCountObj.UNREAD_MSG_COUNT);             } else {                 sendCount.current = 0;             }         },         [sendCount],     );     // 初始化连接socket     const socketInit = useCallback(() => {         try {             const scoketUrl = `wss://${window.location.host}/aapp_socket/${userId}/${token}`;             const socketObj = new WebSocket(scoketUrl);             socketObj.addEventListener('close', socketOnClose);             socketObj.addEventListener('error', socketOnError);             socketObj.addEventListener('message', socketOnMessage);             socketObj.addEventListener('open', socketOnOpen);             socket.current = socketObj;             sendCount.current = 1;         } catch (err) {             console.log('err: ', err);         }     }, [socketOnClose, socketOnError, socketOnMessage, socketOnOpen]);     // 初始化连接socket     useEffect(() => {         socketInit();     }, [socketInit]);     // 断线重连     useEffect(() => {         if (!reset) return;         setTimeout(() => {             socketInit();             setReset(false);         }, 30000);     }, [reset, socketInit]);     return [alarmCount, messageCount]; }; export default useWebSocket;

使用

 // 告警socket连接     const [alarmCount, messageCount] = useWebSocket();

以上为个人经验,希望能给大家一个参考,也希望大家多多支持软件开发网。



websocket React

需要 登录 后方可回复, 如果你还没有账号请 注册新账号