React hook实现简单的websocket封装

  • 新建websocket.ts文件
import {useState, useRef, useEffect} from 'react'

const useWebsocket = ({ url:string, verify }) => {
    const ws = useRef(null)
    // socket 数据
    const [wsData, setMessage] = useState({})
    //  socket 状态
    const [readyState, setReadyState] = useState({ 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,websocket,前端)