Implementing WebSockt via hook is much easier

First of all, when making a requirement, I will check whether there is a shelf. After browsing a lot of articles, I see that it can use socket.io-client on the Internet. And then they go through their own simple encapsulation. The following code

Import IO from 'socket.io-client' import {message} from 'antd' // Socket address and path const URL = 'localhost:8080' const path Export const getClient = () => {if (client) {return client} else { Message. error('socket connection error ')}} // Socket handler persistence let client // socket initialization export const clientInit = async () => { Client = IO (URL, {reconnectionDelayMax: 10000, query: {auth: '123',}, path, TranSports: [' webSocket '], // must be configured})}Copy the code

Then call the following code where the page needs it.

import React, { useState, useEffect } from 'react' import { getClient } from './socket' export default ()=>{ const [socketData ,setSocketData] = useState({}); UseEffect (()=>{// Where type is specified with the backend. GetClient ().on(type,(vl)=>{setSocketData(vl)}) // Page unmount disconnection. return getClient().disconnect() },[]) }Copy the code

Because socket. IO -client function is very powerful, what reconnection, heartbeat, compatibility to get in. But this is also a pit it requires the back end to use socket. IO related interface modification. Otherwise you can’t use it. Always do it with the back end before you do it. Otherwise you really can’t use it. Then it’ll be like me. It’s a long story… I can’t find the picture on site. The problem with this piece is that if the back end of this thing doesn’t use the matching socket. IO, your front end will break immediately. It will always reconnect and keep creating lots of new Websockt requests.

Then there is a follow-up remedy that is to use websockt native hook to build a hook socket,

Hook version of the socket

Let’s just keep it simple and go straight to the code, which will be explained later

import { useState, useRef, useEffect } from 'react' const useWebsocket = ({ url, verify }) => { const ws = useRef(null) const [wsData, setMessage] = useState('') const [readyState, SetReadyState] = useState({key: 0, value: 'on'}) const creatWebSocket = () => {const stateArr = [{key: 0, value: 'on'}) 0, value: 'linking'}, {key: 1, value: 'linking and communicating'}, {key: 2, value: 'connection is closing'}, {key: 3, value: 'Connection closed or no link succeeded'}] try {ws.current = new WebSocket(url) // eslint-disable-next-line @typescript-eslint/no-unused-vars ws.current.onopen = (_e) => setReadyState(stateArr[ws.current?.readyState ?? 0]) // eslint-disable-next-line @typescript-eslint/no-unused-vars ws.current.onclose = (e) => { setReadyState(stateArr[ws.current?.readyState ?? 0]) } // eslint-disable-next-line @typescript-eslint/no-unused-vars ws.current.onerror = (e) => { setReadyState(stateArr[ws.current?.readyState ?? 0]) } ws.current.onmessage = (e) => { setMessage(e.data) } } catch (error) { console.log(error) } } const webSocketInit = () => { if (! Ws. Current | | ws. Current. ReadyState = = = 3) {creatWebSocket ()}} / / close the WebSocket const closeWebSocket = () = > { ws.current? .close() } 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 } } export default useWebsocketCopy the code

As you can see in the code above, I’m exposing four parameters. WsData (obtained socket data), readyState (current socket state), closeWebSocket (closed socket), reconnect (reconnect). These simple parameters can cover the needs of common scenarios. You can then do the following in your code. The verify parameter controls whether you have permission to make a request. You can delete or add them as required. After looking at the native code does it feel quite simple. Reconnection is performed by listening to the readyState state.

import React, { useState, useEffect } from 'react' import useWebsocket from '@/hooks/useWebsocket' export default ()=>{ const [socketData ,setSocketData] = useState({}); const { wsData, readyState, closeWebSocket, reconnect } = useWebsocket({ url: }) useEffect(() => {if (!) => {if (!) => { verify) { return } const { data, Type} = (wsData && JSON. Parse (wsData) | | {} switch (type) {/ / type is agreed with the back-end case 'xxx1: setSocketData ({... socketData, review: data }) break case 'xx2': setSocketData({ ... socketData, pipelineResults: data }) break default: setSocketData({ ... socketData, ... Data break}}) / / if it is closed and is the current page for automatic reconnection if (readyState. Key = = = 3 && isLocalPage) {reconnect ()} / / empty webSocket is not the current page This is used to optimize the code, do not need to delete directly. if (! IsLocalPage) {closeWebSocket()}}, [wsData, readyState, isLocalPage, verify]) for isLocalPage you can see the following code to determine whether the user is on the current page. This method can be placed in useEffect. /* ** Check whether the user leaves the current page, after leaving the polling interface is not requested, Back to the current page to perform polling * / const checkIsLocalPage = () = > {document. The addEventListener (' visibilitychange ', Function () {if (document.visiBilityState === 'hidden') {setIsLocalPage(false)} // If if the page becomes visible (document.visibilityState === 'visible') { setIsLocalPage(true) } }) }Copy the code

Finally, the scenario that is not covered in this code is the heartbeat mechanism. The general simple requirements can be ignored, and this logic is also simple to implement. I won’t elaborate here. Have what good suggestion can comment directly oh ~.