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


    1. 引言

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

    2. 准备工作

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

    npm install websocket
    # 或
    yarn add websocket
    
    • 1
    • 2
    • 3

    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 };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    在上述代码中,我们使用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>
      );
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在上述代码中,我们使用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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在上述代码中,我们使用useWebSocketContext来获取WebSocket连接对象。然后,我们可以在组件中调用send方法来发送消息。

    6. 示例应用:实时聊天

    让我们使用上述代码,创建一个实时聊天应用作为示例。在你的项目中,创建一个名为RealTimeChatApp的文件夹,然后在文件夹中创建以下文件:

    `RealTimeChatApp.js:` 主应用组件
    `ChatComponent.js:` 实时聊天组件
    `WebSocketProvider.js`: `WebSocket`连接提供者
    
    • 1
    • 2
    • 3

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    然后,在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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    最后,启动你的应用,访问RealTimeChatApp组件,即可在浏览器中查看实时聊天功能。

    7. 总结

    本文介绍了如何在React 18应用中使用WebSocket来实现实时通信,并展示了如何通过自定义钩子和提供者模式来共享WebSocket连接对象。通过这种方式,我们可以在多个组件中使用同一个连接对象,从而避免了不必要的连接重复实例化和性能开销。WebSocket在现代实时应用中发挥着重要作用,帮助我们实现更高效的通信和用户体验。

    希望本文能够帮助你理解如何在React 18中使用WebSocket,并在应用中实现共享连接的目标。如果你想进一步探索WebSocket的高级用法,可以深入了解WebSocket的各种选项和特性,以满足你的实际需求。

    致谢

    感谢您阅读本文,希望本文对你有所帮助。特别感谢React 18WebSocket社区的开发者们,为我们提供了强大的工具和技术,让实时通信变得更加简单和高效。

  • 相关阅读:
    初识Vue3
    20221112 今天的世界发生了什么
    SetProxy.bat 设置代理
    时序预测 | MATLAB实现DBN深度置信网络时间序列预测
    洛谷 P3966 [TJOI2013]单词(AC自动机, fail 树)
    数据化运营02 告别迷茫!北极星指标,为业务指明方向
    当知识管理遇上企业云盘一体机
    shell脚本的条件判断3:探究[[]]和[]的区别
    基于HTTP2/3的流模式消息交换如何实现?
    时间序列分析|数据裁剪和滚动异常值检测
  • 原文地址:https://blog.csdn.net/m0_73117087/article/details/134369336