亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2022年09月14日 10:23:59   作者:bigHead-  
這篇文章主要介紹了React?hook實(shí)現(xiàn)簡單的websocket封裝方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(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)閉或者沒有連接成功'},
? ? ? ? ]
? ? ? ? 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(重連)

通過這幾個(gè)簡單的參數(shù)能夠覆蓋一般場景的需要。其中 verify 參數(shù)是控制是否有權(quán)限進(jìn)行請求??梢愿鶕?jù) 實(shí)際需求進(jìn)行刪除或新增。

重連啥的通過監(jiān)聽 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)限,請求該方法
??? ? })
?? ?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)前頁面自動重連
?? ? ? ?if (readyState.key === 3 && isLocalPage) {
?? ? ? ? ?reconnect()
?? ? ? ?}
?? ? ? ?// 不是當(dāng)前頁面 清空 webSocket 此處為優(yōu)化代碼使用的,不需要可以直接刪除。
?? ? ? ?if (!isLocalPage) {
?? ? ? ? ?closeWebSocket()
?? ? ? ?}
? ?? ?}, [wsData, readyState, isLocalPage, verify])
? }

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

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

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

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

react自定義hook,useWebSocket

1、描述

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

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

target:ws目標(biāo)地址、pathRewrite:地址重寫,這里是把/aapp_socket重寫成aapp/websocket,ws:是否開啟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í)際的訪問的地址就是:

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

2、代碼

這里socket,沒有配置心跳監(jiān)測,還是通過我主動去推送來獲取信息。這里是獲取告警數(shù)和消息數(shù)量,

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

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

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

? ? // 開啟事件,主動獲取數(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);
? ? ? ? ? ? // 判斷返回告警保持連接否則斷開連接
? ? ? ? ? ? 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 ant-design Select組件下拉框map不顯示的解決

    react ant-design Select組件下拉框map不顯示的解決

    這篇文章主要介紹了react ant-design Select組件下拉框map不顯示的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • React?正確使用useCallback?useMemo的方式

    React?正確使用useCallback?useMemo的方式

    這篇文章主要介紹了React?正確使用useCallback?useMemo的方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-08-08
  • React超詳細(xì)講述Fiber的使用

    React超詳細(xì)講述Fiber的使用

    在fiber出現(xiàn)之前,react的架構(gòu)體系只有協(xié)調(diào)器reconciler和渲染器render。當(dāng)前有新的update時(shí),react會遞歸所有的vdom節(jié)點(diǎn),如果dom節(jié)點(diǎn)過多,會導(dǎo)致其他事件影響滯后,造成卡頓。即之前的react版本無法中斷工作過程,一旦遞歸開始無法停留下來
    2023-02-02
  • react函數(shù)組件類組件區(qū)別示例詳解

    react函數(shù)組件類組件區(qū)別示例詳解

    這篇文章主要為大家介紹了react函數(shù)組件類組件區(qū)別示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • React tsx生成隨機(jī)驗(yàn)證碼

    React tsx生成隨機(jī)驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了React tsx生成隨機(jī)驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • 使用react-native-image-viewer實(shí)現(xiàn)大圖預(yù)覽

    使用react-native-image-viewer實(shí)現(xiàn)大圖預(yù)覽

    這篇文章主要介紹了使用react-native-image-viewer實(shí)現(xiàn)大圖預(yù)覽,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09
  • React中setState的使用與同步異步的使用

    React中setState的使用與同步異步的使用

    這篇文章主要介紹了React中setState的使用與同步異步的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • React?中的列表渲染要加?key的原因分析

    React?中的列表渲染要加?key的原因分析

    這篇文章主要介紹了React?中的列表渲染為什么要加?key,在?React?中我們經(jīng)常需要渲染列表,比如展示好友列表,文中給大家介紹了列表渲染不提供?key?會如何,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友一起看看吧
    2022-07-07
  • 基于antd的autocomplete的二次封裝查詢示例

    基于antd的autocomplete的二次封裝查詢示例

    這篇文章主要為大家介紹了基于antd的autocomplete的二次封裝查詢示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • 在React項(xiàng)目中使用iframe嵌入一個(gè)網(wǎng)站的步驟

    在React項(xiàng)目中使用iframe嵌入一個(gè)網(wǎng)站的步驟

    本文介紹了如何在React項(xiàng)目中通過iframe嵌入百度網(wǎng)站的步驟,首先創(chuàng)建一個(gè)Baidu.js組件,并在該組件中設(shè)置iframe來加載百度,然后在App.js中引入并使用Baidu組件,還討論了因安全策略可能無法加載某些網(wǎng)站的問題,需要的朋友可以參考下
    2024-09-09

最新評論