最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

React?hook實(shí)現(xiàn)簡(jiǎn)單的websocket封裝方式

 更新時(shí)間:2022年09月14日 10:23:59   作者:bigHead-  
這篇文章主要介紹了React?hook實(shí)現(xiàn)簡(jiǎn)單的websocket封裝方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

React hook實(shí)現(xiàn)websocket封裝

新建websocket.ts文件

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

const useWebsocket = ({ url:string, verify }) => {
? ? const ws = useRef<WebSocket | null>(null)
? ? // socket 數(shù)據(jù)
? ? const [wsData, setMessage] = useState({})
? ? // ?socket 狀態(tài)
? ? const [readyState, setReadyState] = useState<any>({ key: 0, value: '正在連接中' })

? ? const creatWebSocket = () => {
? ? ? ? const stateArr = [
? ? ? ? ? ? {key: 0, value: '正在連接中'},
? ? ? ? ? ? {key: 1, value: '已經(jīng)連接并且可以通訊'},
? ? ? ? ? ? {key: 2, value: '連接正在關(guān)閉'},
? ? ? ? ? ? {key: 3, value: '連接已關(guān)閉或者沒(méi)有連接成功'},
? ? ? ? ]
? ? ? ? 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()
? ? ? ? }
? ? }

? ? // ?關(guān)閉 WebSocket
? ? const closeWebSocket = () => {
? ? ? ? ws.current?.close()
? ? }

? ? // 發(fā)送數(shù)據(jù)
? ? 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

這里一共暴露出四個(gè)參數(shù)。分別是

  • wsData(獲得的 socket 數(shù)據(jù))
  • readyState(當(dāng)前 socket 狀態(tài))
  • closeWebSocket (關(guān)閉 socket)
  • reconnect(重連)

通過(guò)這幾個(gè)簡(jiǎn)單的參數(shù)能夠覆蓋一般場(chǎng)景的需要。其中 verify 參數(shù)是控制是否有權(quán)限進(jìn)行請(qǐng)求。可以根據(jù) 實(shí)際需求進(jìn)行刪除或新增。

重連啥的通過(guò)監(jiān)聽(tīng) readyState 狀態(tài)進(jìn)行相應(yīng)操作。

下面代碼為使用方法:

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:端口', // 此參數(shù)為websocket地址
? ? ?? ?verify // 此參數(shù)控制是否有權(quán)限,請(qǐng)求該方法
??? ? })
?? ?useEffect(() => {
? ? ?? ?// 不在白名單人員之間不執(zhí)行后續(xù)操作,不需要可以刪除
? ? ?? ?if (!verify) {
? ? ? ?? ??? ?return
?? ? ? ?}
?? ? ? ?
?? ? ? ?// 接受到socket數(shù)據(jù), 進(jìn)行業(yè)務(wù)邏輯處理
?? ? ? ?if (Object.keys(wsData).length !== 0) {
?? ? ? ??? ?console.log(wsData)
?? ? ? ?}
?? ? ? ?
?? ? ? ?// 如果是已關(guān)閉且是當(dāng)前頁(yè)面自動(dòng)重連
?? ? ? ?if (readyState.key === 3 && isLocalPage) {
?? ? ? ? ?reconnect()
?? ? ? ?}
?? ? ? ?// 不是當(dāng)前頁(yè)面 清空 webSocket 此處為優(yōu)化代碼使用的,不需要可以直接刪除。
?? ? ? ?if (!isLocalPage) {
?? ? ? ? ?closeWebSocket()
?? ? ? ?}
? ?? ?}, [wsData, readyState, isLocalPage, verify])
? }

對(duì)于 isLocalPage 感興趣可以看下面代碼是判斷用戶是否在當(dāng)前頁(yè)面。 此方法可以放在useEffect。

/*
?** 判斷用戶是否離開(kāi)當(dāng)前頁(yè)面,離開(kāi)后不請(qǐng)求輪詢接口,回到當(dāng)前頁(yè)面重新執(zhí)行輪詢
?*/
useEffect(() => {
? ? ? document.addEventListener('visibilitychange', function () {
? ? ? ? ? // 頁(yè)面變?yōu)椴豢梢?jiàn)時(shí)觸發(fā)
? ? ? ? ? if (document.visibilityState === 'hidden') {
? ? ? ? ? ? ? setIsLocalPage(false)
? ? ? ? ? }
? ? ? ? ? // 頁(yè)面變?yōu)榭梢?jiàn)時(shí)觸發(fā)
? ? ? ? ? if (document.visibilityState === 'visible') {
? ? ? ? ? ? ? setIsLocalPage(true)
? ? ? ? ? }
? ? ? })
? })

最后,在這個(gè)代碼中沒(méi)有涉及到的場(chǎng)景就是 心跳機(jī)制,一般簡(jiǎn)單的需求可以不考慮,這塊邏輯實(shí)現(xiàn)上也比較簡(jiǎn)單,這里就不多加闡述了。 

react自定義hook解決websocket連接,useWebSocket

react自定義hook,useWebSocket

1、描述

本來(lái)項(xiàng)目的告警和消息提醒是用的接口30秒調(diào)用一次,這次要改成webSocket傳輸。

因?yàn)榍岸耸怯玫膆ttps,后端用的http,后端的socket只支持ws不支持wss,這里使用了webpack-dev-server的proxy代理了一下。

target:ws目標(biāo)地址、pathRewrite:地址重寫(xiě),這里是把/aapp_socket重寫(xiě)成aapp/websocket,ws:是否開(kāi)啟socket,secure: 默認(rèn)情況下不接收轉(zhuǎn)發(fā)到https的服務(wù)器上,如果希望支持,可以設(shè)置為false ,changeOrigin:是否跨域。差不多就這個(gè)意思

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

使用連接的地址:

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

實(shí)際的訪問(wèn)的地址就是:

`ws://xxx.xxx.xxx/aapp/websocket

2、代碼

這里socket,沒(méi)有配置心跳監(jiān)測(cè),還是通過(guò)我主動(dòng)去推送來(lái)獲取信息。這里是獲取告警數(shù)和消息數(shù)量,

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

還可以把獲取消息的時(shí)間間隔,和重新連接間隔,地址等變量抽出來(lái),作為參數(shù)傳進(jìn)來(lái)。

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

const token = window.localStorage.getItem('authorization');
const userId = JSON.parse(window.localStorage.getItem('userInfo') || '')?.id;
// 獲取告警數(shù)量
const UNREAD_WARN_COUNT = 'UNREAD_WARN_COUNT';
// 獲取消息數(shù)量
const UNREAD_MSG_COUNT = 'UNREAD_MSG_COUNT';
// 獲取消息的間隔
const INT_TIME = 5000;
// websocket狀態(tài)
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);

? ? // 開(kāi)啟事件,主動(dòng)獲取數(shù)據(jù)
? ? const socketOnOpen = useCallback(() => {
? ? ? ? // 判斷連接狀態(tài)是不是open
? ? ? ? if (socket?.current?.readyState === webSocketStatus.OPEN) {
? ? ? ? ? ? // 第一次加載觸發(fā)一次
? ? ? ? ? ? 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);
? ? ? ? // 返回信息出錯(cuò)清除定時(shí)器
? ? ? ? if (sendCount.current === 0) {
? ? ? ? ? ? clearInterval(timer);
? ? ? ? ? ? setReset(true);
? ? ? ? }
? ? }, [sendCount]);

? ? // 關(guān)閉事件重新連接
? ? const socketOnClose = useCallback(() => {
? ? ? ? setReset(true);
? ? }, []);

? ? // 出錯(cuò)事件
? ? const socketOnError = useCallback((err: any) => {
? ? ? ? console.log('err: ', err);
? ? }, []);

? ? // 收發(fā)信息
? ? const socketOnMessage = useCallback(
? ? ? ? (e: any) => {
? ? ? ? ? ? if (e.data === 'success') return;
? ? ? ? ? ? const alarmCountObj = JSON.parse(e.data);
? ? ? ? ? ? const paramNameArr = Object.keys(alarmCountObj);
? ? ? ? ? ? // 判斷返回告警保持連接否則斷開(kāi)連接
? ? ? ? ? ? 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();

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解React中的不可變值

    詳解React中的不可變值

    這篇文章主要介紹了React中的不可變值的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用react.js,感興趣的朋友可以了解下
    2021-04-04
  • react批量引入svg圖標(biāo)的方法

    react批量引入svg圖標(biāo)的方法

    這篇文章主要介紹了react批量引入svg圖標(biāo)的方法,在批量引入之前,我們需要安裝一個(gè)包并配置到typescript.json文件中,需要的朋友可以參考下
    2024-03-03
  • 淺析history 和 react-router 的實(shí)現(xiàn)原理

    淺析history 和 react-router 的實(shí)現(xiàn)原理

    react-router 版本更新非常快,但是它的底層實(shí)現(xiàn)原理確是萬(wàn)變不離其中,在本文中會(huì)從前端路由出發(fā)到 react-router 原理總結(jié)與分享,本文對(duì)history 和 react-router實(shí)現(xiàn)原理講解的非常詳細(xì),需要的朋友跟隨小編一起看看吧
    2023-08-08
  • react-native?父函數(shù)組件調(diào)用類子組件的方法(實(shí)例詳解)

    react-native?父函數(shù)組件調(diào)用類子組件的方法(實(shí)例詳解)

    這篇文章主要介紹了react-native?父函數(shù)組件調(diào)用類子組件的方法,通過(guò)詳細(xì)步驟介紹了React 函數(shù)式組件之父組件調(diào)用子組件的方法,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • react?中?mobx的使用案例詳解

    react?中?mobx的使用案例詳解

    這篇文章主要介紹了react?中?mobx的使用案例詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • 詳解React中傳入組件的props改變時(shí)更新組件的幾種實(shí)現(xiàn)方法

    詳解React中傳入組件的props改變時(shí)更新組件的幾種實(shí)現(xiàn)方法

    這篇文章主要介紹了詳解React中傳入組件的props改變時(shí)更新組件的幾種實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • ReactNative頁(yè)面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼

    ReactNative頁(yè)面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼

    本篇文章主要介紹了ReactNative頁(yè)面跳轉(zhuǎn)Navigator實(shí)現(xiàn)的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • React中使用antd組件的方法

    React中使用antd組件的方法

    antd?是基于?Ant?Design?設(shè)計(jì)體系的?React?UI?組件庫(kù),主要用于研發(fā)企業(yè)級(jí)中后臺(tái)產(chǎn)品,這篇文章主要介紹了React中使用antd組件,需要的朋友可以參考下
    2022-09-09
  • React Native Popup實(shí)現(xiàn)示例

    React Native Popup實(shí)現(xiàn)示例

    本文主要介紹了React Native Popup實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • React超詳細(xì)分析useState與useReducer源碼

    React超詳細(xì)分析useState與useReducer源碼

    我正在處理的組件是表單的時(shí)間輸入。表單相對(duì)復(fù)雜,并且是動(dòng)態(tài)生成的,根據(jù)嵌套在其他數(shù)據(jù)中的數(shù)據(jù)顯示不同的字段。我正在用useReducer管理表單的狀態(tài),到目前為止效果很好
    2022-11-11

最新評(píng)論

苏尼特左旗| 山丹县| 安西县| 政和县| 岱山县| 米易县| 民权县| 正安县| 绥江县| 宜都市| 仁化县| 定边县| 平乐县| 精河县| 兴安盟| 巩留县| 始兴县| 镇远县| 临江市| 行唐县| 霸州市| 上栗县| 普兰县| 卫辉市| 渑池县| 若羌县| 万盛区| 柳州市| 莱阳市| 南靖县| 昌图县| 肃南| 揭东县| 华宁县| 宁阳县| 嘉峪关市| 方城县| 榕江县| 商都县| 青龙| 乐山市|