websocket-react使用

问题

在一个应用中,如果需要在不同的组件之间共享同一个WebSocket连接,可以采用多种方法来实现。

比如:单例模式、全局变量、react context

React上下文(React Context)

如果你使用的是React,可以使用React Context来共享WebSocket连接。通过创建一个WebSocket上下文,可以在整个应用中提供和消费这个WebSocket连接。

js 复制代码
// WebSocketContext.js
import React, { createContext, useContext, useEffect, useState } from 'react';

const WebSocketContext = createContext(null);

export const WebSocketProvider = ({ children }) => {
    const [socket, setSocket] = useState(null);

    useEffect(() => {
        const ws = new WebSocket('ws://example.com/socket');
        setSocket(ws);

        return () => {
            ws.close();
        };
    }, []);

    return (
        <WebSocketContext.Provider value={socket}>
            {children}
        </WebSocketContext.Provider>
    );
};

export const useWebSocket = () => {
    return useContext(WebSocketContext);
};

// Component1.js
import React from 'react';
import { useWebSocket } from './WebSocketContext';

const Component1 = () => {
    const socket = useWebSocket();

    useEffect(() => {
        if (socket) {
            socket.addEventListener('message', handleMessage);
        }
        return () => {
            if (socket) {
                socket.removeEventListener('message', handleMessage);
            }
        };
    }, [socket]);

    const handleMessage = (event) => {
        console.log('Message in Component 1:', event.data);
    };

    return <div>Component 1</div>;
};

export default Component1;

// Component2.js
import React from 'react';
import { useWebSocket } from './WebSocketContext';

const Component2 = () => {
    const socket = useWebSocket();

    useEffect(() => {
        if (socket) {
            socket.addEventListener('message', handleMessage);
        }
        return () => {
            if (socket) {
                socket.removeEventListener('message', handleMessage);
            }
        };
    }, [socket]);

    const handleMessage = (event) => {
        console.log('Message in Component 2:', event.data);
    };

    return <div>Component 2</div>;
};

export default Component2;

// App.js
import React from 'react';
import { WebSocketProvider } from './WebSocketContext';
import Component1 from './Component1';
import Component2 from './Component2';

const App = () => {
    return (
        <WebSocketProvider>
            <Component1 />
            <Component2 />
        </WebSocketProvider>
    );
};

export default App;

实例

WebSocketContext.ts

ts 复制代码
// contexts/WebSocketContext.ts

import React from 'react';
import WebSocketService from '../services/WebSocketService';

// 此处允许值为 null
const WebSocketContext = React.createContext<WebSocketService | null>(null);

export default WebSocketContext;

WebSocketService.ts

ts 复制代码
import { GetServerVersionResponse } from '@renderer/ipc/renderer_to_main_ipc_invoker/proxy/fpp'

type CallbackFunction = (message: any) => void;
type InvokeDevIpFilesResponse = {
    path: string
    folder: boolean
  }

class WebSocketService {
  public static instance: WebSocketService;
  public ws: WebSocket;
  public listeners: Record<string, CallbackFunction[]>;

  public constructor(url: string) {
    this.ws = new WebSocket(url);
    this.listeners = {};

    // 设置WebSocket事件监听器  
    this.ws.onmessage = this.handleMessage.bind(this);
    this.ws.onopen = this.handleOpen.bind(this);
    this.ws.onerror = this.handleError.bind(this);
    this.ws.onclose = this.handleClose.bind(this);
  }

  public static getInstance(url?: string): WebSocketService {
    if (!WebSocketService.instance) {
        if (!url) {
            throw new Error("WebSocketService instance has not been created yet. Please provide a URL.");
          }
      WebSocketService.instance = new WebSocketService(url);
    }
    return WebSocketService.instance;
  }

  public sendCommand(command: object): void {
    if (this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(command));
    } else {
      console.error('WebSocket is not open.');
    }
  }

  public subscribe(command: string, callback: CallbackFunction): void {
    if (!this.listeners[command]) {
      this.listeners[command] = [];
    }
    this.listeners[command].push(callback);
  }

  public unsubscribe(command: string, callback: CallbackFunction): void {
    if (this.listeners[command]) {
      const index = this.listeners[command].indexOf(callback);
      if (index !== -1) {
        this.listeners[command].splice(index, 1);
      }
    }
  }
  //接收消息并处理
  private handleMessage(event: MessageEvent): void {
    const message = JSON.parse(event.data);
    console.log(message)
    if ( message.version ) {
      this.triggerCallbacks('version', message);
    } else if(Array.isArray(message)){
        const bagsList = message
        .filter(item => item.path && item.path.endsWith('.bag')) 
        .map(item => item.path); 
        if(bagsList){
            this.triggerCallbacks('bags', message);
        }
    }
    // 其他消息类型 在这里添加类似的处理逻辑
  }

  private triggerCallbacks(eventType: string, message: any): void {
    if (this.listeners[eventType]) {
      this.listeners[eventType].forEach((callback) => {
        callback(message);
      });
    }
  }


  private handleOpen(): void {
    console.log('WebSocket connected.');
  }

  private handleError(error: Event): void {
    console.error('❓ WebSocket error:', error);
  }

  private handleClose(): void {
    console.log('❌ WebSocket disconnected.');
  }

  public close(): void {
    this.ws.close();
  }
  

public getGuiVersion(): Promise<string> {
    return new Promise((resolve, reject) => {
      const handleVersionMessage = (message: any) => {
        if (message.version) {
          resolve(message.version);
          this.unsubscribe('version', handleVersionMessage);
        }
      };

      this.subscribe('version', handleVersionMessage);
      this.sendCommand({ command: 'version' });

      setTimeout(() => {
        reject(new Error('Timeout waiting for GUI version.'));
        this.unsubscribe('version', handleVersionMessage);
      }, 5000);
    });
  }

  public getBagsList(): Promise<InvokeDevIpFilesResponse[]> {
    return new Promise((resolve, reject) => {
      const handleBagsMessage = (message: any) => {
        console.log(message)
          resolve(message);
          this.unsubscribe('bags', handleBagsMessage);
        
      };
  
      this.subscribe('bags', handleBagsMessage);
      const command = {
        command: 'bags',
        pattern: '*'
      };
      this.sendCommand(command);
  
      setTimeout(() => {
        reject(new Error('Timeout waiting for bags list.'));
        this.unsubscribe('bags', handleBagsMessage);
      }, 5000);
    });
  }

  public getMvizLink(): Promise<GetServerVersionResponse> {
    return new Promise((resolve, reject) => {
      const handleBagsMessage = (message: any) => {
        console.log(message)
          resolve(message);
          this.unsubscribe('bags', handleBagsMessage);
        
      };
  
      this.subscribe('bags', handleBagsMessage);
      const command = {
        command: 'bags',
        pattern: '*'
      };
      this.sendCommand(command);
  
      setTimeout(() => {
        reject(new Error('Timeout waiting for bags list.'));
        this.unsubscribe('bags', handleBagsMessage);
      }, 5000);
    });
  }

}

export default WebSocketService;

App.js

js 复制代码
// App.js 或其他顶层组件

import React from 'react';
import WebSocketContext from './contexts/WebSocketContext';
import WebSocketService from './services/WebSocketService';

function App() {
  // 创建 WebSocketService 实例, 可以在这里传递你需要连接的WebSocket服务器的URL
  const webSocketInstance = WebSocketService.getInstance('ws://your-websocket-url');

  return (
    // 使用 WebSocketContext.Provider 包裹你的组件并传递 value
    <WebSocketContext.Provider value={webSocketInstance}>
      {/* 这里是其他组件 */}
    </WebSocketContext.Provider>
  );
}

export default App;

// SomeComponent.jsx

js 复制代码
// SomeComponent.jsx

import React, { useContext } from 'react';
import WebSocketContext from './contexts/WebSocketContext';

function SomeComponent() {
  // 使用 useContext 钩子获取 WebSocketService 实例
  const webSocket = useContext(WebSocketContext);
  
  // 接下来可以使用 webSocket 发送消息或订阅事件
  // ...

  return (
    // 组件的其余部分
  );
}

export default SomeComponent;

(占个坑,后续更新一下)

相关推荐
前端小小王8 分钟前
React Hooks
前端·javascript·react.js
迷途小码农零零发18 分钟前
react中使用ResizeObserver来观察元素的size变化
前端·javascript·react.js
zquwei2 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring
真滴book理喻3 小时前
Vue(四)
前端·javascript·vue.js
程序员_三木4 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
不是鱼5 小时前
构建React基础及理解与Vue的区别
前端·vue.js·react.js
开心工作室_kaic5 小时前
springboot476基于vue篮球联盟管理系统(论文+源码)_kaic
前端·javascript·vue.js
川石教育5 小时前
Vue前端开发-缓存优化
前端·javascript·vue.js·缓存·前端框架·vue·数据缓存
搏博5 小时前
使用Vue创建前后端分离项目的过程(前端部分)
前端·javascript·vue.js
温轻舟6 小时前
前端开发 之 12个鼠标交互特效上【附完整源码】
开发语言·前端·javascript·css·html·交互·温轻舟