react使用websocket實時通信方式
使用websocket實時通信
在react中使用websocket不需要引入其他庫,只需要創(chuàng)建一個公共組件,封裝一下websocket
創(chuàng)建公共組件
websocket.js
let websocket, lockReconnect = false; let createWebSocket = (url) => { ? ? websocket = new WebSocket(url); ? ? websocket.onopen = function () { ? ? ? ?heartCheck.reset().start(); ? ? } ? ? websocket.onerror = function () { ? ? ? ? reconnect(url); ? ? }; ? ? websocket.onclose = function (e) { ? ? ? ? console.log('websocket 斷開: ' + e.code + ' ' + e.reason + ' ' + e.wasClean) ? ? } ? ? websocket.onmessage = function (event) { ? ? ? ? lockReconnect=true; ? ? ? ? //event 為服務端傳輸的消息,在這里可以處理 ? ? } } let reconnect = (url) => { ? ? if (lockReconnect) return; ? ? //沒連接上會一直重連,設置延遲避免請求過多 ? ? setTimeout(function () { ? ? ? ? createWebSocket(url); ? ? ? ? lockReconnect = false; ? ? }, 4000); } let heartCheck = { ? ? timeout: 60000, //60秒 ? ? timeoutObj: null, ? ? reset: function () { ? ? ? ? clearInterval(this.timeoutObj); ? ? ? ? return this; ? ? }, ? ? start: function () { ? ? ? ? this.timeoutObj = setInterval(function () { ? ? ? ? ? ? //這里發(fā)送一個心跳,后端收到后,返回一個心跳消息, ? ? ? ? ? ? //onmessage拿到返回的心跳就說明連接正常 ? ? ? ? ? ? websocket.send("HeartBeat"); ? ? ? ? }, this.timeout) ? ? } } //關閉連接 let closeWebSocket=()=> { ? ? websocket && websocket.close(); } export { ? ? websocket, ? ? createWebSocket, ? ? closeWebSocket };
在react組件中的使用
1.react 函數組件的使用
import {createWebSocket,closeWebSocket} from './websocket'; const Element=(param)=>{ ?? ?useEffect(()=>{ ?? ??? ?let url="";//服務端連接的url ?? ??? ?createWebSocket(url) ?? ??? ?//在組件卸載的時候,關閉連接 ?? ??? ? return ()=>{ ? ? ? ? ? ? closeWebSocket(); ? ? ? ? } ?? ?}) }
2.react 類組件中的使用
import {createWebSocket,closeWebSocket} from './websocket'; .... componentDidMount(){ ??? ?let url="";//服務端連接的url ?? ?createWebSocket(url) ?} ?componentWillUnmount(){ ?? ? closeWebSocket(); } ....
如果一個連接,推送不同的消息如何處理?
1.需要安裝 pubsub-js
2.修改webscocket.js 獲取消息的代碼
import { PubSub } from 'pubsub-js'; ... ?websocket.onmessage = function (event) { ? ? ? ? lockReconnect=true; ? ? ? ? //event 為服務端傳輸的消息,在這里可以處理 ? ? ? ? let data=JSON.parse(event.data);//把獲取到的消息處理成字典,方便后期使用 ? ? ? ? PubSub.publish('message',data); //發(fā)布接收到的消息 'message' 為發(fā)布消息的名稱,data 為發(fā)布的消息 ? ?} ? ?...
3.在組件中的使用
函數組件中的使用(在類組件中類似)
import { PubSub } from 'pubsub-js'; useEffect(()=>{ ?? ?//訂閱 'message' 發(fā)布的發(fā)布的消息 ?? ?messageSocket = PubSub.subscribe('message', function (topic,message) {? ?? ??? ?//message 為接收到的消息 ?這里進行業(yè)務處理 ?? ?}) ?? ?//卸載組件 取消訂閱 ?? ?return ()=>{ ? ? ? ? ? PubSub.unsubscribe(messageSocket);? ? ? } }
websocket在不同情形下的使用
1.在react中使用websocket
在項目根目錄中創(chuàng)建一個websocket文件夾用于封裝公用組件
代碼如下:
/** ?* 參數:[socketOpen|socketClose|socketMessage|socketError] = func,[socket連接成功時觸發(fā)|連接關閉|發(fā)送消息|連接錯誤] ?* timeout:連接超時時間 ?* @type {module.webSocket} ?*/ class webSocket { ? ? constructor(param = {}) { ? ? ? ? this.param = param; ? ? ? ? this.reconnectCount = 0; ? ? ? ? this.socket = null; ? ? ? ? this.taskRemindInterval = null; ? ? ? ? this.isSucces=true; ? ? } ? ? connection = () => { ? ? ? ? let {socketUrl, timeout = 0} = this.param; ? ? ? ? // 檢測當前瀏覽器是什么瀏覽器來決定用什么socket ? ? ? ? if ('WebSocket' in window) { ? ? ? ? ? ? console.log('WebSocket'); ? ? ? ? ? ?? ? ? ? ? ? ? this.socket = new WebSocket(socketUrl); ? ? ? ? } ? ? ? ? else if ('MozWebSocket' in window) { ? ? ? ? ? ? console.log('MozWebSocket'); ? ? ? ? ? ? // this.socket = new MozWebSocket(socketUrl); ? ? ? ? } ? ? ? ? else { ? ? ? ? ? ? console.log('SockJS'); ? ? ? ? ? ?? ? ? ? ? ? ? // this.socket = new SockJS(socketUrl); ? ? ? ? } ? ? ? ? this.socket.onopen = this.onopen; ? ? ? ? this.socket.onmessage = this.onmessage; ? ? ? ? this.socket.onclose = this.onclose; ? ? ? ? this.socket.onerror = this.onerror; ? ? ? ? this.socket.sendMessage = this.sendMessage; ? ? ? ? this.socket.closeSocket = this.closeSocket; ? ? ? ? // 檢測返回的狀態(tài)碼 如果socket.readyState不等于1則連接失敗,關閉連接 ? ? ? ? if(timeout) { ? ? ? ? ? ? let time = setTimeout(() => { ? ? ? ? ? ? ? ? ?if(this.socket && this.socket.readyState !== 1) { ? ? ? ? ? ? ? ? ? ? ?this.socket.close(); ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ?clearInterval(time); ? ? ? ? ? ? }, timeout); ? ? ? ? } ? ? }; ? ? // 連接成功觸發(fā) ? ? onopen = () => { ? ? ? ? let {socketOpen} = this.param; ? ? ? ? this.isSucces=false ?//連接成功將標識符改為false ? ? ? ? socketOpen && socketOpen(); ? ? }; ? ? // 后端向前端推得數據 ? ? onmessage = (msg) => { ? ? ? ? let {socketMessage} = this.param; ? ? ? ? socketMessage && socketMessage(msg); ? ? ? ? // 打印出后端推得數據 ? ? ? ? console.log(msg); ? ? }; ? ? // 關閉連接觸發(fā) ? ? onclose = (e) => { ? ? ? ? this.isSucces=true ? //關閉將標識符改為true ? ? ? ? console.log('關閉socket收到的數據'); ? ? ? ? let {socketClose} = this.param; ? ? ? ? socketClose && socketClose(e); ? ? ? ? // 根據后端返回的狀態(tài)碼做操作 ? ? ? ? // 我的項目是當前頁面打開兩個或者以上,就把當前以打開的socket關閉 ? ? ? ? // 否則就20秒重連一次,直到重連成功為止? ? ? ? ? if(e.code=='4500'){ ? ? ? ? ? ? this.socket.close(); ? ? ? ? }else{ ? ? ? ? ? ? this.taskRemindInterval = setInterval(()=>{ ? ? ? ? ? ? ? ? if(this.isSucces){ ? ? ? ? ? ? ? ? ? ? this.connection(); ? ? ? ? ? ? ? ? }else{ ? ? ? ? ? ? ? ? ? ? clearInterval(this.taskRemindInterval) ? ? ? ? ? ? ? ? } ? ? ? ? ? ? },20000) ? ? ? ? } ? ? }; ? ? onerror = (e) => { ? ? ? ? // socket連接報錯觸發(fā) ? ? ? ? let {socketError} = this.param; ? ? ? ? this.socket = null; ? ? ? ? socketError && socketError(e); ? ? }; ? ? sendMessage = (value) => { ? ? ? ? // 向后端發(fā)送數據 ? ? ? ? if(this.socket) { ? ? ? ? ? ? this.socket.send(JSON.stringify(value)); ? ? ? ? } ? ? }; }; export { ? ? webSocket, ? }
這樣就完成了websocket的全局功能組件封裝,在需要用的組件進行引用就行了
例:
import {webSocket} from "../../WebSocket/index"; //函數調用 WebSocketTest=()=>{ ? ? ? ? // ? ?判斷專家是否登錄 ? ? ? ? let that = this; ? ? ? ? let userId = JSON.parse(localStorage.getItem("adminInfo")).id; ? ? ? ? console.log(userId) ? ? ? ? this.socket = new webSocket({ ? ? ? ? ? ? socketUrl: 'ws://xx.xxx.xxx/imserver/'+userId, ? ? ? ? ? ? timeout: 5000, ? ? ? ? ? ? socketMessage: (receive) => { ? ? ? ? ? ? ? ? console.log(receive) ? ? ? ? ? ? ? ? // if(receive.data === '1'){ ? ? ? ? ? ? ? ? // ? ? console.log(receive); ?//后端返回的數據,渲染頁面 ? ? ? ? ? ? ? ? // }else if(JSON.parse(receive.data)){ ? ? ? ? ? ? ? ? // ? ? that.setState({msgData:receive.data}) ? ? ? ? ? ? ? ? // }else{ ? ? ? ? ? ? ? ? // ? ? message.info("有新消息了") ? ? ? ? ? ? ? ? // } ? ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? if (typeof JSON.parse(receive.data) == "object") { ? ? ? ? ? ? ? ? ? ? ? ? that.setState({msgData:receive.data}) ? ? ? ? ? ? ? ? ? ? }else if(receive.data === '1'){ ? ? ? ? ? ? ? ? ? ? ? ? console.log(receive.data); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } catch(e) { ? ? ? ? ? ? ? ? ? ? message.info(receive.data) ? ? ? ? ? ? ? ? } ? ? ? ? ? ? }, ? ? ? ? ? ? socketClose: (msg) => { ? ? ? ? ? ? ? ? console.log(msg); ? ? ? ? ? ? }, ? ? ? ? ? ? socketError: () => { ? ? ? ? ? ? ? ? console.log(this.state.taskStage + '連接建立失敗'); ? ? ? ? ? ? ? ? message.error("消息通信連接失敗,建議刷新") ? ? ? ? ? ? }, ? ? ? ? ? ? socketOpen: () => { ? ? ? ? ? ? ? ? console.log('連接建立成功'); ? ? ? ? ? ? ? ? // 心跳機制 定時向后端發(fā)數據 ? ? ? ? ? ? ? ? this.taskRemindInterval = setInterval(() => { ? ? ? ? ? ? ? ? ? ? this.socket.sendMessage({ "msgType": 0 }) ? ? ? ? ? ? ? ? }, 30000) ? ? ? ? ? ? } ? ? ? ? }); //重試創(chuàng)建socket連接 ? ? ? ? try { ? ? ? ? ? ? this.socket.connection(); ? ? ? ? } catch (e) { ? ? ? ? ? ? // 捕獲異常,防止js error ? ? ? ? ? ? // donothing ? ? ? ? } ? ? }
2.websocket在小程序中使用
小程序官方文檔里是有相關的組件和調用方法,所以這里就不詳細介紹了,簡單說一下我的理解和使用方法。
在項目根目錄下創(chuàng)建websocket文件
const app = getApp(); import { webSocketUrl } from '../utils/requst/url'; //websocket封裝模塊 const lqoWS = { ? openSocket(val) { ? ? let wsData = app.globalData.wsData; ? ? //我這里向后端傳參用的路徑參數,所以這里稍微設置一下 ? ? let urls = '' ? ? if(val == '/userSocket/'){ ? ? ? urls = webSocketUrl + val + wsData.id ? ? } ? ? if(val == '/ownerSocket/'){ ? ? ? urls = webSocketUrl + val + wsData.id + '/' + wsData.lon + '/' + wsData.lat; ? ? } ? ? //打開時的動作 ? ? ?wx.onSocketOpen(() => { ? ? ? ?console.log('WebSocket 已連接') ? ? ? ?app.globalData.socketStatus = 'connected'; ? ? ? ?this.sendMessage(val); ? ? ?}) ? ? ?//斷開時的動作 ? ? ?wx.onSocketClose(() => { ? ? ? ?console.log('WebSocket 已斷開') ? ? ? ?if(app.globalData.socketStatus == 'closeds'){ ? ? ? ? return ? ? ? } ? ? ? ?app.globalData.socketStatus = 'closed'; ? ? ? ?this.pdSocketOpen(val); ? ? ?}) ? ? ?//報錯時的動作 ? ? ?wx.onSocketError(error => { ? ? ? ?console.error('socket error:', error) ? ? ?}) ? ? ?// 監(jiān)聽服務器推送的消息 ? ? ?wx.onSocketMessage(message => { ? ? ? //把JSONStr轉為JSON ? ? ? message = message.data.replace(" ", ""); ? ? ? ? if (typeof message != 'object') { ? ? ? ? ? ? message = message.replace(/\ufeff/g, ""); //重點 ? ? ? ? ? ? var jj = JSON.parse(message); ? ? ? ? ? ? message = jj; ? ? ? ? } ? ? ? ?console.log(message) ? ? ?}) ? ? ?// 打開信道 ? ? ?wx.connectSocket({ ? ? ? url: urls, ? ? ? success:(res)=>{ ? ? ? ? console.log(res) ? ? ? } ? ? ?}) ? ?}, ? ? ? ?//關閉信道 ? ?closeSocket(val) { ? ? ?if (app.globalData.socketStatus == 'connected') { ? ? ? ?wx.closeSocket({ ? ? ? ? ?success: () => { ? ? ? ? ? app.globalData.socketStatus = 'closeds' ? ? ? ? ?} ? ? ? ?}) ? ? ?} ? ?}, ? ? ? ? //發(fā)送消息函數 ? ?sendMessage(val) { ? ? ?if (app.globalData.socketStatus == 'connected') { ? ? ?//自定義的發(fā)給后臺識別的參數 ,我這里發(fā)送的是name ? ? ? ?wx.sendSocketMessage({ ? ? ? ? // ?data: "{\"name\":\"" + '123' + "\"}"? ? ? ? ? data: app.globalData.wsData ? ? ? ?}) ? ? ?} ? ?}, ? ?pdSocketOpen (val) { ? ? setTimeout(() => { ? ? ? if(app.globalData.socketStatus == 'closed'){ ? ? ? ? // console.log(app.globalData.socketStatus) ? ? ? ? this.openSocket(val); ? ? ? } ? ? }, 4000) ? }, } export { ? lqoWS, }
使用
代碼里的相關參數需要在全局中進行設置
import { lqoWS } from '../../websoket/index'; let val = '/ownerSocket/'; ? ? if(app.globalData.socketStatus == 'closed'){ ? ? ? ? // that.openSocket(); ? ? ? ? lqoWS.openSocket(val); ? ? } ? ? // lqoWS.closeSocket(val); ? ? lqoWS.sendMessage(val); ? ? lqoWS.pdSocketOpen(val);
小程序官方有非常詳細的使用說明。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
在 React 項目中使用 Auth0 并集成到后端服務的配置步驟詳解
這篇文章主要介紹了在 React 項目中使用 Auth0 并集成到后端服務的配置步驟詳解,通過本文詳細步驟,您可以將 Auth0 集成到 React 項目并與后端服務交互,需要的朋友可以參考下2024-07-07從零開始搭建webpack+react開發(fā)環(huán)境的詳細步驟
這篇文章主要介紹了從零開始搭建webpack+react開發(fā)環(huán)境的詳細步驟,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05解決React報錯Parameter 'props' implicitly&nb
這篇文章主要為大家介紹了React報錯Parameter 'props' implicitly has an 'any' type的解決處理方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12一文詳解如何使用React監(jiān)聽網絡狀態(tài)
在現代Web應用程序中,網絡連接是至關重要的,通過監(jiān)聽網絡狀態(tài),我們可以為用戶提供更好的體驗,例如在斷網時顯示有關網絡狀態(tài)的信息,本文將介紹如何使用React監(jiān)聽網絡狀態(tài)的變化,并提供相應的代碼示例2023-06-06Hello?React的組件化方式之React入門小案例演示
這篇文章主要介紹了Hello?React的組件化方式-React入門小案例,本文通過Hello?React的案例,?來體驗一下React開發(fā)模式,?以及jsx的語法,需要的朋友可以參考下2022-10-10