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;

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

相关推荐
软件技术NINI4 分钟前
如何使用 Vue 3 的 Composition API
前端·javascript·vue.js
猿究院+5 分钟前
Vue3中的监听器。toRefs与toRef的区别
前端·javascript·vue.js
LJPchosen16 分钟前
el-tree组件进来的时候默认展开并且滚动定位到展开项的位置
前端·javascript·vue.js
向上的时钟塔39 分钟前
Vue3 el-switch @change事件在初始化时会自动调用问题
前端·javascript·vue.js
好哈优学编程1 小时前
JavaScript知识点3
开发语言·前端·javascript
软件技术NINI1 小时前
JavaScript网页设计案例
javascript
Fan_web2 小时前
JavaScript高级——作用域和作用链
开发语言·前端·javascript·css·html
不会做饭的程序员3 小时前
前端项目使用js将dom生成图片、PDF
前端·javascript·pdf
CiL#3 小时前
el-table表格的展开行,初始化的时候展开哪一行+设置点击行可展开功能
前端·javascript·vue.js
waterHBO4 小时前
React js Router 路由 2, (把写过的几个 app 组合起来)
前端·javascript·react.js