React 分装webSocket

背景 AI 实时对话 需要流式数据

React Hooks 写法。新建WebSocket.tsx   放在根目录components

import { useCallback, useRef, useState } from 'react';type MessageHandler = (message: MessageEvent) => void;
type ErrorHandler = (event: Event) => void;export function useWebSocket(url: string,onMessage: MessageHandler,onError?: ErrorHandler,token?: string, // 新增 token 参数
) {const [isConnected, setIsConnected] = useState<boolean>(false);const [reconnectAttempts, setReconnectAttempts] = useState<number>(0);const [messages, setMessages] = useState<string[]>([]); // 用于存储消息const websocketRef = useRef<WebSocket | null>(null);const reconnectTimeoutRef = useRef<number | null>(null);const isManualClose = useRef<boolean>(false); // 改用 useRef 防止异步更新问题// 最大重连次数const maxReconnectAttempts = 5;// 初始重连延迟时间(毫秒)const initialReconnectDelay = 1000;// 连接 WebSocketconst connectWebSocket = useCallback(() => {isManualClose.current = false; // 每次连接时重置手动关闭状态// 如果有 token,则通过 URL 查询参数传递const wsUrl = token ? `${url}?token=${token}` : url;websocketRef.current = new WebSocket(wsUrl);websocketRef.current.onopen = () => {console.log('WebSocket连接成功');setIsConnected(true);setReconnectAttempts(0); // 连接成功后重置重连次数};websocketRef.current.onmessage = (event: MessageEvent) => {onMessage(event);setMessages((prevMessages) => [...prevMessages, event.data]); // 将消息保存到状态};websocketRef.current.onerror = (event: Event) => {console.error('WebSocket发生错误:', event);if (onError) onError(event); // 如果提供了 onError 回调,调用它};websocketRef.current.onclose = () => {console.log('WebSocket连接关闭');setIsConnected(false);// 判断是否需要重连,只有在非手动断开时才尝试重连if (isManualClose.current) {console.log('WebSocket手动关闭,不进行重连');return; // 终止重连逻辑}if (reconnectAttempts < maxReconnectAttempts) {const delay = initialReconnectDelay * Math.pow(2, reconnectAttempts); // 指数级递增延迟console.log(`Reconnecting in ${delay / 1000} seconds...`);reconnectTimeoutRef.current = window.setTimeout(() => {setReconnectAttempts((prev) => prev + 1);connectWebSocket(); // 重试连接}, delay);} else {console.error('WebSocket重连失败次数过多,停止重连');}};}, [url, token, onMessage, onError, reconnectAttempts]);// 手动断开 WebSocket 连接const disconnectWebSocket = useCallback(() => {if (websocketRef.current) {console.log('手动断开 WebSocket 连接');isManualClose.current = true; // 使用 ref 直接设置为手动关闭websocketRef.current.close();if (reconnectTimeoutRef.current) {clearTimeout(reconnectTimeoutRef.current); // 清除任何重连的定时器}}}, []);// 发送消息const sendMessage = useCallback((message: string) => {if (websocketRef.current &&websocketRef.current.readyState === WebSocket.OPEN) {websocketRef.current.send(message);} else {console.warn('WebSocket is not open.');}}, []);return {isConnected, // 是否已连接sendMessage, // 发送消息的函数disconnectWebSocket, // 手动断开连接的函数connectWebSocket, // 手动连接函数messages, // 返回存储的消息};
}

使用

import { useWebSocket } from '@/components/WebSocket';  //自己的文件路径
import { useEffect, useState } from 'react';
const AiChat = () => {const [isDialogue, setIsDialogue] = useState<boolean>(true);const {isConnected,sendMessage,disconnectWebSocket,connectWebSocket,messages,} = useWebSocket('wss://service-guide-uat.yadea.com.cn/ws', (message) => {console.log('Received message:', message.data);});const handleConnect = () => {console.log('手动触发连接');connectWebSocket(); // 手动触发连接};useEffect(() => {connectWebSocket();return () => {console.log('手动触发关闭');disconnectWebSocket();};}, []);return (<div className={style.box}>测试</div>);
};export default AiChat;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/455149.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

技术成神之路:设计模式(二十二)命令模式

介绍 命令模式&#xff08;Command Pattern&#xff09;是一种行为设计模式&#xff0c;允许将请求&#xff08;命令&#xff09;封装为对象&#xff0c;从而使您可以使用不同的请求、队列或记录请求日志&#xff0c;以及支持可撤销操作。 1. 定义 命令模式将一个请求封装为一个…

S32DS for ARM GPIO实践

S32DS操作&#xff1a; 一、新建项目 打开S32DS&#xff0c;FIle–>NEW–> S32DS Application Project选择对应芯片&#xff0c;写入项目名然后下一步 选择对应的SDK&#xff0c;Debugger选带有PE字眼的&#xff0c;点击完成 配置GPIO&#xff0c;双击Components界面下的…

【MySQL】详解MySQL数据类型

一、数据类型 各类型的数值范围&#xff1a; 在MySQL中&#xff0c;整型可以指定是有符号的和无符号的&#xff0c;默认是有符号的。 可以通过UNSIGNED来说明某个字段是无符号的。对于int类型可能存放不下的数据&#xff0c;尽量不使用unsigned&#xff0c;unsigned int 同样可…

pytorch dataloader学习

import torch from torch.utils.data import Dataset, DataLoader import numpy as np torch.manual_seed(1) # 自定义数据集 class CustomDataset(Dataset):def __init__(self):# 创建一些示例数据&#xff08;100个样本&#xff0c;每个样本包含10个特征&#xff09;self.dat…

推荐一个开源非线性视频编辑器:Kdenlive

Kdenlive是一个开源的视频编辑软件&#xff0c;项目始于约2003年。它基于Qt和KDE框架库构建&#xff0c;大部分视频处理由MLT框架完成&#xff0c;同时依赖其他开源项目如FFmpeg、frei0r、movit、ladspa、sox等。 软件特点&#xff1a; - 多轨视频编辑&#xff1a;支持多个音频…

MongoDB Shell 基本命令(三)生成学生脚本信息和简单查询

一、生成学生信息脚本 利用该脚本可以生成任意个学生信息&#xff0c;包括学号、姓名、班级、年级、专业、课程名称、课程成绩等信息&#xff0c;此处生成2万名学生&#xff0c;学生所有信息都是给定范围后随机生成。 生成学生信息后&#xff0c;再来对学生信息进行简单查询。…

论文阅读:Guided Linear Upsampling

今天介绍一篇有趣的文章&#xff0c;Guided Linear Upsampling&#xff0c;基于引导的线性上采样&#xff0c;这是发表在 ACM transaction on Graphic 的一篇工作。 Abstract 引导上采样是加速高分辨率图像处理的一种有效方法。在本文中&#xff0c;文章作者提出了一种简单而…

【2024】【字节青训营】:字节青训营入营测试题——Java版本(已提交通过)

目录 简单题目 计算x到y的最小步数 环状 DNA 序列的最小表示法 Base32 解码和编码 打点计时器 兔群繁殖之谜 完美整数 找出整数数组中占比超过 一半 的数 找出最长的神奇数列 找单独的数 字符串最短循环字串 二进制反码转换问题 中等题目 简单四则运算 数字翻译…

【图解版】力扣第146题:LRU缓存

力扣第146题&#xff1a;LRU缓存 一、LRU算法1. 基本概念2. LRU 和 LFU 的区别&#xff1a;3. 为什么 LRU 不需要记录使用频率&#xff1f; 二、Golang代码实现三、代码图解1. LRUCache、DLinkedNode两个结构体2. 初始化结构体对象3. addToHead函数4. removeNode函数5. moveToH…

rust grpc demo

文章目录 1. 创建项目2. 配置proto2.1 配置Cargo.toml, 内容如下&#xff1a;2.2 创建文件proto/hello.proto, 内容如下&#xff1a;2.3 添加build.rs文件&#xff0c; 内容如下&#xff1a;2.4 项目结构如下&#xff1a;2.5 编译proto文件 3.0 处理服务3.1 项目引入3.2 添加sr…

多模态大语言模型(MLLM)-Deepseek Janus

论文链接&#xff1a;https://arxiv.org/abs/2410.13848 代码链接&#xff1a;https://github.com/deepseek-ai/Janus 本次解读Janus: Decoupling Visual Encoding for Unified Multimodal Understanding and Generation 前言 Deepseek出品&#xff0c;必属精品。 创新点 传…

docker容器无法连接宿主机mysql排查

1、docker无法访问宿主机 在docker容器内&#xff0c;需要访问当前docker容器的网关&#xff0c;例如172.xx.0.1&#xff0c;即可访问宿主机&#xff0c;因此需要保证docker的网络配置正确 查看当前docker容器的网关&#xff1a; docker inspect 你的容器名或者容器id 显示…

【纯前端excel导出】vue2纯前端导出excel,使用xlsx插件,修改样式、合并单元格

官网&#xff1a; 1、xlsx-js-style xlsx-js-style | xlsx-js-style homepage 2、xlsx SheetJS 中文网 一、使用第三方插件 1、安装 npm install xlsx-js-style 2、引入 import xlsx from xlsx-js-style xlsx插件是基础的导出&#xff0c;不可以修改样式&#xff0c;直接xlsx-s…

文通车牌识别相机在工地称重应用中的卓越表现

在现代工地管理中&#xff0c;高效、准确的称重系统是确保工程顺利进行的关键之一。而文通车牌识别相机的出现&#xff0c;为工地称重应用带来了全新的解决方案。 一、工地称重面临的挑战 传统的工地称重方式往往存在着一些问题。人工记录车牌和重量信息容易出现错误&#xff0…

python-----函数详解(一)

一、概念及作用&#xff1a; 概念&#xff1a;由若干条语句组成语句块&#xff0c;其中包括函数名称、参数列表&#xff0c;它是组织代码的最小单元&#xff0c;完成一定的功能 作用&#xff1a;把一个代码封装成一个函数&#xff0c;一般按功能组织一段代码 目的就是为了重…

基于单片机的智能小区门禁系统设计(论文+源码)

1总体架构 智能小区门禁系统以STM32单片机和WiFi技术为核心&#xff0c;STM32单片机作为主控单元&#xff0c;通过WiFi模块实现与手机APP的连接&#xff0c;构建整个门禁系统。系统硬件包括RFID模块、指纹识别模块、显示屏、按键以及继电器。通过RFID绑定IC卡、APP面部识别、指…

百度搜索推广和信息流推广的区别,分别适用于什么场景!

信息流推广和搜索广告&#xff0c;不仅仅是百度&#xff0c;是很多平台的两个核心推广方式。 1、搜索广告&#xff1a; 就是基于用户的搜索习惯&#xff0c;更多是用户有疑问、还有用户当下就要做出行动的广告。 比如上门服务、线上咨询服务、招商加盟、了解产品各种型号和信…

STM32G4系列MCU的低功耗模式介绍

目录 概述 1 认识低功耗模式 1.1 低功耗模式的应用 1.2 低功耗模式介绍 2 低功耗模式的状态关系 2.1 低功耗模式可能的转换状态图 2.2 低功耗模式总结 3 运行模式 3.1 减慢系统时钟 3.2 外围时钟门控 3.3 低功耗运行模式&#xff08;LP运行&#xff09; 概述 本文主…

react 基础学习笔记

1.react 语法 ①数据渲染 函数组件将HTML结构直接写在函数的返回值中 JSX只能有一个根元素 JSX插值写法 插值可以使用的位置 1.标签内容&#xff1b; 2.标签属性 JSX 条件渲染&#xff1a;三目运算符&#xff1b; JSX根据数据进行列表渲染&#xff1a;map()方法&#x…

QT 机器视觉 1.相机类型

本专栏从实际需求场景出发详细还原、分别介绍大型工业化场景、专业实验室场景、自动化生产线场景、各种视觉检测物体场景介绍本专栏应用场景 更适合涉及到视觉相关工作者、包括但不限于一线操作人员、现场实施人员、项目相关维护人员&#xff0c;希望了解2D、3D相机视觉相关操作…