使用React 18和WebSocket构建实时通信功能
1. 引言
WebSocket
是一种在Web
应用中实现双向通信的协议。它允许服务器主动向客户端推送数据,而不需要客户端发起请求。在现代的实时应用中,WebSocket
经常用于实时数据传输、聊天功能、实时通知和多人协作等场景。在本篇博客中,我们将探索如何在React 18
应用中使用WebSocket
来实现实时通信。
2. 准备工作
在开始之前,我们需要安装React 18
,并确定你已经掌握了React Hooks
的基本知识。此外,我们还将使用WebSocket
的npm包来实现WebSocket
连接。你可以通过以下命令使用npm
或yarn
来安装它:
npm install websocket
# 或
yarn add websocket
3. 编写自定义钩子
import { useEffect, useRef, useState } from 'react';
import WebSocketClient from 'websocket';export function useWebSocket(accessToken: string, requestName: string): SocketType {const clientRef = useRef<WebSocketClient | null>(null);const [isActive, setIsActive] = useState<boolean>(false);const [socketClient, setSockClient] = useState<WebSocketClient | null>(null);// 获取urllet port = window.location.port;let wsUrl = '';if (window.location.protocol === 'https:') {//如果当前是HTTPS加密的,那么使用wssif (!port) {port = '4174';}wsUrl = 'wss:';} else {if (!port) {port = '8080';}wsUrl = 'ws:';}wsUrl +=`//${window.location.hostname}:${port}/api/ws/plugins/${requestName}?token=` +accessToken;if (!socketClient) {setSockClient(new WebSocketClient(wsUrl, isActive)); // 创建 WebSocketClient 实例并传入 URL 和活动状态 isActive}useEffect(() => {clientRef.current = socketClient;if (!socketClient?.socket) {socketClient?.start(); // 启动WebSocket连接}return () => {socketClient?.close(); // 组件卸载时关闭WebSocket连接};}, []);// 建立 WebSocket 连接const connect = () => {const client = clientRef.current;if (client) {client.connect(); // 建立WebSocket连接}};// 关闭 WebSocket 连接const close = () => {const client = clientRef.current;if (client) {client.close(); // 关闭WebSocket连接}};// 订阅消息处理程序const subscribe = (handler: MessageHandler) => {const client = clientRef.current;setIsActive(true);if (client) {client.subscribe(handler);}};// 取消订阅消息const unsubscribe = () => {const client = clientRef.current;if (client && isActive) {setIsActive(false);client.unsubscribe();}};// 发送消息const send = (message: string) => {const client = clientRef.current;if (client && client.socket?.readyState === WebSocket.OPEN) {client.send(message); // 发送消息} else if (client && client.socket?.readyState === WebSocket.CLOSED) {// WebSocket连接未建立或已关闭,需要重新建立连接client.connect(); // 建立WebSocket连接}};return { connect, close, subscribe, unsubscribe, send };
}
在上述代码中,我们使用useRef
来保存WebSocketClient
实例,使用useState来管理isActive
和socketClient
状态。通过创建WebSocket
连接的URL和accessToken
,我们可以在useEffect钩子中实例化WebSocketClient
。然后使用useEffect
钩子来启动和关闭WebSocket连接,并在组件卸载时关闭连接。
4. 创建WebSocketProvider
为了在整个应用中共享WebSocket
连接对象,我们需要创建一个WebSocketProvider
组件。这个组件将使用提供者模式将连接对象提供给子组件。
在你的项目中创建一个名为WebSocketProvider
.js的文件,并添加以下代码:
import React, { useContext, useEffect } from 'react';
import { useWebSocket } from './useWebSocket';const WebSocketContext = React.createContext();export const useWebSocketContext = () => {return useContext(WebSocketContext);
};export const WebSocketProvider = ({ children, accessToken }) => {const webSocket = useWebSocket(accessToken);useEffect(() => {webSocket.connect();return () => {webSocket.close();};}, [webSocket]);return (<WebSocketContext.Provider value={webSocket}>{children}</WebSocketContext.Provider>);
};
在上述代码中,我们使用useWebSocket
钩子来获取WebSocket
连接对象,并在useEffect
钩子中连接WebSocket
,并在组件卸载时关闭连接。然后,我们将连接对象提供给子组件,通过创建一个WebSocketContext.Provider
。
5. 在组件中使用共享连接
现在,我们可以在应用的任何组件中使用共享的WebSocket
连接了。
假设我们有一个名为ChatComponent
的组件,它需要使用WebSocket
连接来实现实时聊天功能。在ChatComponent.js
文件中,添加以下代码:
import React from 'react';
import { useWebSocketContext } from './WebSocketProvider';function ChatComponent() {const webSocket = useWebSocketContext();const sendMessage = () => {if (webSocket) {webSocket.send('Hello, WebSocket!');}};return (<div><button onClick={sendMessage}>Send Message</button></div>);
}export default ChatComponent;
在上述代码中,我们使用useWebSocketContext
来获取WebSocket
连接对象。然后,我们可以在组件中调用send
方法来发送消息。
6. 示例应用:实时聊天
让我们使用上述代码,创建一个实时聊天应用作为示例。在你的项目中,创建一个名为RealTimeChatApp
的文件夹,然后在文件夹中创建以下文件:
`RealTimeChatApp.js:` 主应用组件
`ChatComponent.js:` 实时聊天组件
`WebSocketProvider.js`: `WebSocket`连接提供者
在RealTimeChatApp.js
中,添加以下代码:
import React from 'react';
import ChatComponent from './ChatComponent';
import { WebSocketProvider } from './WebSocketProvider';function RealTimeChatApp() {const accessToken = 'your_access_token'; // 替换为你的访问令牌return (<WebSocketProvider accessToken={accessToken}><div><h1>Real Time Chat App</h1><ChatComponent /></div></WebSocketProvider>);
}export default RealTimeChatApp;
然后,在ChatComponent.js
中,添加以下代码:
import React from 'react';
import { useWebSocketContext } from './WebSocketProvider';
function ChatComponent() {const webSocket = useWebSocketContext();const [messages, setMessages] = React.useState([]);const [newMessage, setNewMessage] = React.useState('');React.useEffect(() => {const messageHandler = (message) => {setMessages((prevMessages) => [...prevMessages, message]);};webSocket.subscribe(messageHandler);return () => {webSocket.unsubscribe();};}, [webSocket]);const sendMessage = () => {if (webSocket) {webSocket.send(newMessage);setNewMessage('');}};return (<div><div>{messages.map((message, index) => (<div key={index}>{message}</div>))}</div><div><inputtype="text"value={newMessage}onChange={(e) => setNewMessage(e.target.value)}/><button onClick={sendMessage}>Send</button></div></div>);
}export default ChatComponent;
最后,启动你的应用,访问RealTimeChatApp
组件,即可在浏览器中查看实时聊天功能。
7. 总结
本文介绍了如何在React 18
应用中使用WebSocket
来实现实时通信,并展示了如何通过自定义钩子和提供者模式来共享WebSocket
连接对象。通过这种方式,我们可以在多个组件中使用同一个连接对象,从而避免了不必要的连接重复实例化和性能开销。WebSocket
在现代实时应用中发挥着重要作用,帮助我们实现更高效的通信和用户体验。
希望本文能够帮助你理解如何在React 18
中使用WebSocket
,并在应用中实现共享连接的目标。如果你想进一步探索WebSocket
的高级用法,可以深入了解WebSocket
的各种选项和特性,以满足你的实际需求。
致谢
感谢您阅读本文,希望本文对你有所帮助。特别感谢React 18
和WebSocket
社区的开发者们,为我们提供了强大的工具和技术,让实时通信变得更加简单和高效。
相关文章:
使用React 18和WebSocket构建实时通信功能
1. 引言 WebSocket是一种在Web应用中实现双向通信的协议。它允许服务器主动向客户端推送数据,而不需要客户端发起请求。在现代的实时应用中,WebSocket经常用于实时数据传输、聊天功能、实时通知和多人协作等场景。在本篇博客中,我们将探索如…...
vue3使用vue-router嵌套路由(多级路由)
文章目录 1、Vue3 嵌套路由2、项目结构3、编写相关页面代码3.1、编写route文件下 index.ts文件3.2、main.ts文件代码:3.3、App.vue文件代码:3.4、views文件夹下的Home文件夹下的index.vue文件代码:3.5、views文件夹下的Home文件夹下的Tigerhh…...
openGauss学习笔记-164 openGauss 数据库运维-备份与恢复-导入数据-使用COPY FROM STDIN导入数据-处理错误表
文章目录 openGauss学习笔记-164 openGauss 数据库运维-备份与恢复-导入数据-使用COPY FROM STDIN导入数据-处理错误表164.1 操作场景164.2 查询错误信息164.3 处理数据导入错误 openGauss学习笔记-164 openGauss 数据库运维-备份与恢复-导入数据-使用COPY FROM STDIN导入数据-…...
QT Widget - 随便画个圆
简介 实现在界面中画一个圆, 其实目的是想画一个LED效果的圆。代码 #include <QApplication> #include <QWidget> #include <QPainter> #include <QColor> #include <QPen>class LEDWidget : public QWidget { public:LEDWidget(QWidget *pare…...
js输入框部分内容不可编辑,其余正常输入,el-input和el-select输入框和多个下拉框联动后的内容不可修改
<tr>//格式// required自定义指令<e-td :required"!read" label><span>地区:</span></e-td><td>//v-if"!read && this.data.nationCode 148"显示逻辑<divclass"table-cell-flex"sty…...
分布式文件存储系统minio了解下
什么是minio minio 是一个基于 Apache License v2.0 开源协议的对象存储服务。非常适合于存储大容量非结构化的数据,例如图片、视频、日志文件、备份数据和容器/虚拟机镜像等,而一个对象文件可以是任意大小。 是一种海量、安全、低成本、高可靠的云存储…...
迅为RK3568开发板使用OpenCV处理图像-ROI区域-位置提取ROI
在图像处理过程中,我们可能会对图像的某一个特定区域感兴趣,该区域被称为感兴趣区域(Region of Interest, ROI)。在设定感兴趣区域 ROI 后,就可以对该区域进行整体操作。 位置提取 ROI 本小节代码在配套资料“iTOP-3…...
重新认识Word——尾注
重新认识Word——尾注 参考文献格式文献自动生成器插入尾注将数字带上方括号将参考文献中的标号改为非上标 多处引用一篇文献多篇文献被一处引用插入尾注有横线怎么删除?删除尾注 前面我们学习了如何给图片,公式自动添加编号,今天我们来看看毕…...
所有学前教育专业,一定要刷到这篇啊
我是真的希望所有学前教育的宝子都能刷到这篇啊啊,只要输入需求,几秒它就给你写出来了,而且不满意还可以重新写多,每次都是不一样的内容。重复率真的不高,需求越多,生成的文字内容越精准!&#…...
colmap三维重建核心逻辑梳理
colmap三维重建核心逻辑梳理 1. 算法流程束流2. 初始化3. 重建主流程 1. 算法流程束流 重建核心逻辑见 incremental_mapper.cc 中 IncrementMapperController 中 Reconstruct 初始化变量和对象判断是否有初始重建模型,若有,则获取初始重建模型数量&am…...
查询某个类是在哪个JAR的什么版本开始出现的方法
背景 我们在依赖第三方JAR时,同时也会间接的依赖第三方JAR引用的依赖,而当我们项目中某个依赖的版本与第三方JAR依赖的版本不一致时,可能会导致第三方JAR的在运行时无法找到某些方法或类,从而无法正常使用。 如我正在开发的一个…...
Linux本地搭建StackEdit Markdown编辑器结合内网穿透实现远程访问
文章目录 1. docker部署Stackedit2. 本地访问3. Linux 安装cpolar4. 配置Stackedit公网访问地址5. 公网远程访问Stackedit6. 固定Stackedit公网地址 StackEdit是一个受欢迎的Markdown编辑器,在GitHub上拥有20.7k Star!,它支持将Markdown笔记保…...
k8s中ConfigMap、Secret创建使用演示、配置文件存储介绍
目录 一.ConfigMap(cm) 1.适用场景 2.创建并验证configmap (1)以yaml配置文件创建configmap,验证变化是是否同步 (2)--from-file以目录或文件 3.如何使用configmap (1&#x…...
Linux服务器性能优化小结
文章目录 生产环境监测常见专业名词扫盲服务器平均负载服务器平均负载的定义如何判断平均负载值以及好坏情况如果依据平均负载来判断服务器当前状况系统平均负载和CPU使用率的区别 CPU上下文切换基本概念3种上下文切换进程上下文切换线程上下文切换中断上下文切换 查看上下文切…...
ELF文件结构
ELF文件结构 前文结尾说到编译器编译源代码后生成的文件叫做目标文件,而目标文件经过编译器链接之后得到的就是可执行文件。那么目标文件到底是什么?它和可执行文件又有什么区别?链接到底又做了什么呢?接下来,我们将探…...
【C++】有关string迭代器的几道OJ题详解
目录 一、字符串最后一个单词的长度 题目描述 完整代码 二、验证回文串 题目描述 完整代码 三、反转字符串 题目描述 完整代码 四、反转字符串中的单词 题目描述 完整代码 一、字符串最后一个单词的长度 原题链接 题目描述 计算字符串最后一个单词的长度ÿ…...
谷歌宣布向云计算客户开放 Gemini Pro,开发者可用其构建应用
12 月 14 日消息,美国时间周三,谷歌宣布了一系列升级的人工智能(AI)功能,旨在为其云计算客户提供更好的服务。这家科技巨头正试图赶上竞争对手,比如微软和 OpenAI,它们都在积极利用人工智能的热…...
软件测试用例经典方法 | 单元测试法案例
单元测试又称模块测试,是对软件设计的最小单元的功能、性能、接口和设计约束等的正确性进行检验,检查程序在语法、格式和逻辑上的错误,并验证程序是否符合规范,以发现单元内部可能存在的各种缺陷。 单元测试的对象是软件设计的最…...
Leetcode 2967. Minimum Cost to Make Array Equalindromic
Leetcode 2967. Minimum Cost to Make Array Equalindromic 1. 解题思路2. 代码实现 题目链接:2967. Minimum Cost to Make Array Equalindromic 1. 解题思路 这一题其实我的思路有点笨,多少有点暴力求解的意思。 显然,如果我们给出全部的…...
【数据结构】什么是堆?
🦄个人主页:修修修也 🎏所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 堆的概念及结构 堆的定义如下: n个元素的序列{k1,k2,...,kn}当且仅当满足以下关系时,称之为堆. 或 把这个序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个…...
生产环境_Spark处理轨迹中跨越本初子午线的经度列
使用spark处理数据集,解决gis轨迹点在地图上跨本初子午线的问题,这个问题很复杂,先补充一版我写的 import org.apache.spark.{SparkConf, SparkContext} import org.apache.spark.sql.{Row, SparkSession} import org.apache.spark.sql.func…...
Vue前端与后端放在一起的搭建方式
1.首先把后端项目搭建好 去到项目的存放位置 2.然后cmd黑窗口输入命令创建vue项目 3.创建成功后回到后端项目进行合并 3.1在File处选择Project Structure 3.2选择模块 3.3找到自己的vue项目 3.4疯狂next最后create 3.5选择Apply并确定OK,恭喜您创建成功了 二、启动…...
SI24R03国产自主可控RISC-V架构MCU低功耗2.4GHz收发芯片SoC
目录 RISC-V架构的优势SI24R03/04特性射频收发器模块特征MCU 模块特征 其他特征 RISC-V架构的优势 相对于目前主流的英特尔X86架构及ARM等架构来说,RISC-V架构具有指令精简、模块化、可扩展、开源、免费等优点。RISC-V的基础指令集只有40多条,加上其他基…...
基于FPGA的温度控制系统设计(论文+源码)
1.系统设计 本次基于FPGA的智能温度控制系统,以FPGA为控制核心,采用自顶向下的设计方法,按照模块化设计的思路分别实现各个模块,再加以整合实现整个系统,从而达到了温度控制的目的。系统以水箱为被控对象,…...
C语言训练:三个字符串比较大小,实现两个整数数的交换统计二进制中1的个数
目录 一、编写程序,输入三个字符串,比较它们的大小,并将它们按由小到大的顺序输出。要求用函数、指针实现。要求:要采用函数调用,并用指向函数的指针作为函数的参数。 1.不使用函数指针作为参数,并自己模拟strcmp。 …...
module ‘tensorflow‘ has no attribute XXX 报错解决
问题描述: 粘了别人的tensorflow项目,运行总是报错module ‘tensorflow’ has no attribute什么什么 问题解决: 导入tensorflow的代码如下 import tensorflow as tf此时,某个某块报错,比如下面这个 那么就直接把tf.…...
MySQL数据库 DDL
目录 一、DDL 二、操作数据库 三、操作表 四、数据类型 五、表操作案例 六、修改表 七、删除表 一、DDL Data Definition Language,数据定义语言,用来定义数据库对象(数据库,表,字段) 。 二、操作数据库 (1&am…...
力扣二叉树--总结篇(2)
前言 总体回顾:11.18-12.14,中间有一个星期左右因为考试没有写题。37道题。 内容 这是第二阶段刷的题 从路径到构造二叉树,合并二叉树,再到二叉搜索树,公共祖先问题 看到二叉树,看到递归 都会想&#…...
小米移动端页面练习---重点:导航栏点击下箭头内容的切换以及样式,高亮显示的实现
效果图 1.html <div><header><div class"header-ad"><img src"./images/ad.png" alt"" srcset""></div><div class"header-two-section"><div class"logo"><div c…...
从零开始创建一个项目,springBoot+mybatisPlus+mysql+swagger+maven
一,前提 从零开始创建一个项目,绑定了数据库 用到的技术栈:springBootmybatisPlusmysqlswaggermaven 二,创建项目步骤 1,创建项目 创建出来的项目结构如图所示 2,修改配置文件 因为我比较习惯yml语言&…...
dedecms 网站根目录/谷歌优化是什么意思
一直很喜欢电脑,开始只是打打游戏,后来逐渐对网络技术产生了兴趣,2001年的中美民间网络战,更激发了我学习网络安全技术的渴望,平时都是逛论坛,看帖子自学,跟着帖子里教的动手去做,有…...
上海网站哪家好/外贸网站
3.设置背景图片 Background-image:url(相对路径) ----123.jpg图片拉伸铺满: background-size:cover 铺满方向: background-repeat:repeat-x/repeat-y/no-repeat(横向铺满/纵向铺满/不铺满显示左上角) 图片方位: backgr…...
广州网络营销选择/赣州seo顾问
Linux Kernel snd_seq_write()函数本地缓冲区溢出漏洞(CVE-2018-7566)发布日期:2018-03-27更新日期:2018-04-11受影响系统:Linux kernel 4.15描述:BUGTRAQ ID: 103605CVE(CAN) ID: CVE-2018-7566Linux Kernel是Linux操作系统的内…...
找个人做网站还是找企业做网站/大连企业黄页电话
BombLabs是CSAPP的第二个Lab,主要考察的是对于汇编的阅读能力。BombLab做起来其实并不难,大概花了大半天就能完成,但确实对于栈的理解会得到提升,并且深深的感受到循环、数组、链表的底层魅力。并且由于对Bomb的忌惮,你…...
怎样制作微信网站/百度区域代理
转自 UML类图几种关系的总结 http://blog.csdn.net/tianhai110/article/details/6339565 转自 UML序列图总结 http://blog.csdn.net/tianhai110/article/details/6361338 在UML的类图中,常见的有以下几种关系: 泛化(Generalization), 实现&am…...
室内设计官方网站/小说推文推广平台
Windows搭建Jenkins详细入门1.下载最新Jenkins下载地址:https://jenkins.io/download/,选择Windows(可以根据自己需要选择对应的系统平台)。 安装之前需要配置jdk环境,详细步骤百度有。2.下载完成后,启动Je…...