本文将一个webSocket封装成hooks的形式,便于使用。
主要思路:
1、根据一个ws/wss地址,创建并初始化一个socket;
2、通过心跳参数heartParam存在与否,判断是否需要对当前socket进行心跳检测;
3、监听异常,socket挂掉后重新创建socket,重复过程1;
4、返回webSocket对象ws和message接收的消息wsData。
/**
* @name useWebSocket
* @export
* @param {url} -(必需)ws/wss地址
* @param {info} -(不必需)socket运行过程中的一些参数,进房参数joinParams,心跳参数heartParams
* @returns
* {ws} -socket对象
* {wsData} -接收的socket消息
*/
import { useEffect, useState, useRef } from 'react'
let lockReconnect = false // 避免重复连接
const heartCheckSecond = 30 * 1000 // 心跳检测间隔时长
function useWebSocket(url, info) {
const [wsData, setWsData] = useState({}) // 接收的消息
const wsRef = useRef(null)
const { joinParams, heartParams } = info??{}
useEffect(() => {
if (!url) return
createWebSocket()
}, [url])
const createWebSocket = () => { // 创建socket连接
wsRef.current = new WebSocket(url)
initWebSocket()
}
const reconnect = () => { // 创建连接,lockReconnect使当前项目只会存在一个socket
if (lockReconnect) return
lockReconnect = true
setTimeout(function () { // 没连接上会一直重连,设置延迟避免请求过多
createWebSocket()
lockReconnect = false
}, 2000)
}
const initWebSocket = () => { // 初始化socket
wsRef.current.onclose = function (evt) { // 关闭
console.log('断开连接code:' + evt.code)
reconnect()
}
wsRef.current.onerror = function (evt) { // 连接错误
console.log('连接失败code:' + evt.code)
reconnect()
}
wsRef.current.onopen = function () {
var dt = new Date()
var str = dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate() + ' ' + dt.getHours() + ':' + dt.getMinutes() + ':' + dt.getSeconds()
console.log('连接成功:' + str)
wsRef.current.send(joinParams) // 发起c.jr进房操作
heartParams && heartCheck.reset().start()
}
wsRef.current.onmessage = function (evt) {
var data = JSON.parse(evt.data) // 接收消息string=>json
setWsData(data)
heartParams && heartCheck.reset().start()
}
}
let heartCheck = { // 心跳检测
timeout: heartCheckSecond,
timeoutObj: null,
serverTimeoutObj: null,
reset: function() {
clearTimeout(this.timeoutObj)
clearTimeout(this.serverTimeoutObj)
return this
},
start: function() {
this.timeoutObj = setTimeout(function() {
// 这里发送一个心跳,后端收到后,返回一个心跳消息,
wsRef.current.send(heartParams)
this.serverTimeoutObj = setTimeout(function() { // 如果超过一定时间还没重置,说明后端主动断开了
wsRef.current.close()
}, this.timeout)
}, this.timeout)
}
}
return [wsRef.current, wsData]
}
export default useWebSocket
import useWebSocket from './useWebSocket'
const [ws, wsData] = useWebSocket(wsUrl, { joinParams: '' })
useEffect(() => {
console.log('webSocket message:', wsData)
}, [wsData])
const handleSendMessage = (params) => { // 向socket发送消息,格式为string
ws.send(JSON.stringify(params))
}