首页 > 其他分享 >使用React 18和WebSocket构建实时通信功能

使用React 18和WebSocket构建实时通信功能

时间:2024-04-01 09:32:45浏览次数:23  
标签:WebSocket 18 React client const 连接 webSocket

1. 引言

WebSocket是一种在Web应用中实现双向通信的协议。它允许服务器主动向客户端推送数据,而不需要客户端发起请求。在现代的实时应用中,WebSocket经常用于实时数据传输、聊天功能、实时通知和多人协作等场景。在本篇博客中,我们将探索如何在React 18应用中使用WebSocket来实现实时通信。

2. 准备工作

在开始之前,我们需要安装React 18,并确定你已经掌握了React Hooks的基本知识。此外,我们还将使用WebSocket的npm包来实现WebSocket连接。你可以通过以下命令使用npmyarn来安装它:

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);
  // 获取url
  let port = window.location.port;
  let wsUrl = '';

  if (window.location.protocol === 'https:') {
    //如果当前是HTTPS加密的,那么使用wss
    if (!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来管理isActivesocketClient状态。通过创建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>
        <input
          type="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 18WebSocket社区的开发者们,为我们提供了强大的工具和技术,让实时通信变得更加简单和高效。

标签:WebSocket,18,React,client,const,连接,webSocket
From: https://blog.csdn.net/m0_73117087/article/details/134369336

相关文章

  • P1618 三连击(升级版)
    题目链接:#include<bits/stdc++.h>usingnamespacestd;intp[10],sum;intmain(){ intA,B,C; boolflag=false; scanf("%d%d%d",&A,&B,&C); for(inti=1;i<=999/C;i++){ memset(p,0,sizeofp); sum=0; ......
  • 6、GB28181
    GB28181是中国国家标准委员会发布的关于视频监控安防领域的网络视频监控系统技术规范,全称是“公共安全视频监控联网系统信息传输、交换、控制技术要求”。该标准规定了公共安全视频监控联网系统的互联结构、传输、交换、控制的基本要求和安全性要求,以及控制、传输流程和协议接口等......
  • 从虚拟dom知识无痛深入vue与react的原理
     我们都知道像vue、react都有用到虚拟dom,那么虚拟dom到底是什么?框架为什么不直接操作真实dom而要在中间要引入虚拟dom呢?vue和react的虚拟dom又有什么异同呢?我们就从虚拟dom开始讲起,再来逐步引入讲解vue与react的部分原理及其异同,这里会顺便讲解到数据驱动视图及视图驱动数据,......
  • 18_makefile基本语法(下)
    makefile基本语法(下)1.wildcard函数格式:$(wildcardPATTENR)功能:展开指定的目录举例:在/home/test目录有一个a.c的c文件和一个test的文件夹,在/home/test/test文件夹下有一个b.c的文件。​ 我们在当前目录下创建的makefile里面写下如下代码,echo前面加了@符号,echo这......
  • React Native简介和环境配置,差点挂在第四面
    ReactNative目前需要NodeJS5.0或更高版本。本文发布时Homebrew默认安装的是最新版本,一般都满足要求。brewinstallnode安装完node后建议设置npm镜像以加速后面的过程(或使用科学上网工具)。注意:不要使用cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!npmconfig......
  • react路径别名@配置
    首先下载包craconpmi-D @craco/craco1.路径解析在项目根目录下创建craco.config.js配置如下2.vscode识别配置在项目根目录下创建jsconfig.json,配置如下3. package.json将start和build的内容改成craco,重启项目 ......
  • 蓝桥杯2018年第十三届省赛真题-复数幂
    一、题目复数幂设i为虚数单位。对于任意正整数n,(2+3i)^n的实部和虚部都是整数。求(2+3i)^123456等于多少?即(2+3i)的123456次幂,这个数字很大,要求精确表示。答案写成"实部±虚部i"的形式,实部和虚部都是整数(不能用科学计数法表示),中间任何地方都不加空格,实部为正时前面......
  • 18day-19day-2.2.CSS实战与提高
    2.2.CSS实战与提高练习11:制作开心餐厅页面CSS/*层次选择器*/p{font-size:14px;}/*body后代h2字体16px*/bodyh2{font-size:16px;}/*第一个h2颜色变为红色*/.firstH2{color:red;}/*第一个h2后面的通用兄弟元素h2变为蓝色*/.firstH2~h2{......
  • 矩阵置零 - LeetCode 热题 18
    大家好!我是曾续缘......
  • react + electron 应用在线更新功能记录
    这个东西很多人都可能用electron-update这个玩意,但是我用了,发现总是更新不了,于是放弃,使用electron自带功能  主进程main.js中引入 const{autoUpdater}=require('electron-updater'); 以下为主要代码,也是放在main.js  autoUpdater.autoDownload=false......