返回顶部
首页 > 资讯 > 前端开发 > JavaScript >React hook实现简单的websocket封装方式
  • 324
分享到

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

2024-04-02 19:04:59 324人浏览 泡泡鱼
摘要

目录React hook实现websocket封装react自定义hook解决WEBSocket连接,useWebSocket1、描述2、代码React hook实现websocke

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();

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: React hook实现简单的websocket封装方式

本文链接: https://lsjlt.com/news/167493.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • React hook实现简单的websocket封装方式
    目录React hook实现websocket封装react自定义hook解决websocket连接,useWebSocket1、描述2、代码React hook实现websocke...
    99+
    2024-04-02
  • vue3中的hook简单封装
    目录vue3的hook封装vue3的hooks总结下面总结一下如何去书写hooks计数器的hookvue3的hook封装 vue3最新鲜的就是组合式API了,通过组合式API我们可以...
    99+
    2024-04-02
  • C++中封装的含义和简单实现方式
    目录封装实现封装属性class 封装其实封装并不是编程中的一个思想,对于很多领域来说都是这样。对于电子器件来说,我们不关心其内部的结构,只在乎该器件能够实现什么样的功能。这样对于顾客...
    99+
    2024-04-02
  • Vue websocket封装实现方法详解
    目录1.封装的ws.js文件2.使用方法1.封装的ws.js文件 let global_callback = null let socket = '' // 存储 WebSocket...
    99+
    2024-04-02
  • js实现封装jQuery的简单方法与链式操作详解
    目录1. 实现$(".box1").click( )方法 2. 实现$("div").click( )方法 3. 考虑$( )中参数的三种情况 4. 实现jq中的on方法 5. 实现...
    99+
    2024-04-02
  • @FeignClient 实现简便http请求封装方式
    目录@FeignClient实现http请求封装使用流程将http请求封装为FeignClient1.配置拦截器2.注入feignClient bean3.配置pom引用4.写fei...
    99+
    2024-04-02
  • React+Typescript实现倒计时Hook的方法
    首先对setInterval做了Hook化封装👇 import { useEffect, useRef } from 'react' function us...
    99+
    2024-04-02
  • java实现简单的webservice方式
    要实现简单的webservice方式,可以使用Java中的JAX-WS(Java API for XML Web Services)...
    99+
    2023-08-15
    Java
  • Android中网络框架简单封装的实例方法
    Android中网络框架的简单封装 前言 Android作为一款主要应用在移动终端的操作系统,访问网络是必不可少的功能。访问网络,最基本的接口有:HttpUrlConnecti...
    99+
    2022-06-06
    方法 封装 框架 Android
  • react实现简单的拖拽功能
    本文实例为大家分享了react实现简单的拖拽功能的具体代码,供大家参考,具体内容如下 src文件夹下新建文件夹demo  然后在创建两个文件js和css demo.js文...
    99+
    2024-04-02
  • vue3学习笔记简单封装axios示例实现
    目录简介openapi基本配置拦截器api请求数据渲染简介 axios是一个基于promise的网络请求库,管理后台使用的场景通常 获取后端api数据,然后交给页面渲染 还是在前面的...
    99+
    2024-04-02
  • 插件化机制优雅封装你的hook请求使用方式
    目录引言useRequest 简介架构useRequest 入口处理Fetch 和 Pluginsstate 以及 setState插件化机制的实现核心方法 —&mdas...
    99+
    2024-04-02
  • 基于React封装组件的实现步骤
    目录前言antd 是如何封装组件的divider 组件源代码如何暴露组件属性如何设置统一类名前缀如何处理样式与类名divider 组件样式源代码前言 很多小伙伴在第一次尝试封装组件时...
    99+
    2024-04-02
  • java怎么实现简单的webservice方式
    Java可以使用Java API for XML Web Services(JAX-WS)来实现简单的Web服务。下面是一个简单的示...
    99+
    2023-08-15
    java
  • vue3.0实现下拉菜单的封装
    vue3.0出来已经有段时间的了,也与必要开始研究它了! 先看下我们要实现的效果 很常见的展开显示菜单项的内容,在vue3.0里面怎么开发,这里样式我们用的是bootstrap的默...
    99+
    2024-04-02
  • java实现两个对象之间传值及简单的封装
    目录java两个对象之间传值及封装java 参数传递、对象、封装面向对象的三大特征封装表现封装的好处构建set、get方法java两个对象之间传值及封装 在项目里面使用SSH框架的过...
    99+
    2024-04-02
  • android第三方分享方式的简单实现
    目前第三方分享方式有两种: 1.需要集成官方sdk包,在获得官方授权后调用其api来完成分享到微信、微博等。     优点:无缝集成,功能多 &...
    99+
    2022-06-06
    Android
  • android实现okHttp的get和post请求的简单封装与使用
    由于Android课程项目需要,特地查阅了okHttp的使用,发现网上找的大多和自己的需求不一样。所以就着团队项目需要,自己简单封装了一个okHttp的get和post请求。 话不多...
    99+
    2024-04-02
  • golang实现一个简单的websocket聊天室功能
    基本原理: 1.引入了 golang.org/x/net/websocket 包。 2.监听端口。 3.客户端连接时,发送结构体: {"type":"login","uid":"我是...
    99+
    2024-04-02
  • Unity实现简单换装系统的方法
    小编给大家分享一下Unity实现简单换装系统的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!代码如下:using UnityEngine;using...
    99+
    2023-06-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作