使用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}当且仅当满足以下关系时,称之为堆. 或 把这个序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...