问题
在一个应用中,如果需要在不同的组件之间共享同一个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;
(占个坑,后续更新一下)