[英]How to implement websocket client in Electron (Next.js/React)?
我有一个工作的 websocket 服务器。 我以前在网络浏览器/反应中使用 websocket 作为客户端,但我无法在电子应用程序中使用 Websocket,因为 WebSocket 取决于浏览器的兼容性,并且由于某种原因,此功能在 Electron 中不可用。
我使用 nextron (nextjs/react + electron) 样板。
yarn create nextron-app MY_APP --example with-typescript-material-ui
import React from 'react';
import Head from 'next/head';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import { theme } from '../lib/theme';
import type { AppProps } from 'next/app';
export default function (props: AppProps) {
const { Component, pageProps } = props;
// where to put ws here ? this placement generates an error
const ws = new WebSocket("ws://192.168.100.8:8081/")
console.log("file: _app.tsx:11 ~ ws", ws)
React.useEffect(() => {
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);
return (
<React.Fragment>
<Head>
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
</Head>
<ThemeProvider theme={theme}>
<CssBaseline />
<Component {...pageProps} />
</ThemeProvider>
</React.Fragment>
);
}
显然是做不到的。 Electron 阻止任何在客户端 (React) 内使用 websocket 的尝试。 到目前为止我使用的唯一解决方案是将 websocket 消息和事件转换为ipcRenderer
( https://www.electronjs.org/docs/latest/api/ipc-renderer )
这个过程相当简单:React 接收一个事件并在客户端调用 IPCRenderer,IPCRenderer 在渲染器(node.js)中接收一个事件并调用 node.js 中的ws
或 websocket
发送:
React -> IPC -> Node.js -> websocket -> Websocket Server (main server)
接收:
Websocket Server (main server) -> websocket -> Node.js -> IPC -> React
我从这里使用 node.js 的ws
模块
我希望这可以帮助将来的人或我自己
如果你想发送/广播事件到 websocket
// in the client side usually the root component, or in my case _app.tsx:
import electron from 'electron'
const ipcRenderer = electron.ipcRenderer
class _app extends React.Component<any, any> {
constructor(props: any) {...}
componentDidMount() {...}
// this will send a message for a button click
handleClick(msg: string) {
// reply will be true if it succeed
let reply = ipcRenderer.sendSync('some-event', msg)
}
}
稍后在主窗口 app.js 中:
import { app, ipcMain } from 'electron'
import WebSocket from 'ws'
// connect with ws
let ws = new WebSocket(`ws://${YOUR_WS_SERVER_IP}:${YOUR_WS_PORT}/`)
// find the electron main window, mine's in background.ts
const mainWindow = createWindow('main', {
width: 1366,
height: 768,
minWidth: 1366,
minHeight: 768
})
// .... some electron code here ....
// when ipcMain receive an event named 'some-event'
ipcMain.on('some-event', (event, msg) => {
ws.send(msg) // send message using websocket here
event.returnValue = true // give a return value true
})
如果你想处理从 websocket 接收到的事件
import { app, ipcMain } from 'electron'
import WebSocket from 'ws'
// connect with ws
let ws = new WebSocket(`ws://${YOUR_WS_SERVER_IP}:${YOUR_WS_PORT}/`)
// find the electron main window, mine's in background.ts
const mainWindow = createWindow('main', {
width: 1366,
height: 768,
minWidth: 1366,
minHeight: 768
})
ws.on("message", (message: any) => {
var str = message.toString()
console.log("Message received: ", str)
mainWindow.webContents.send('some-event', str)
})
在反应组件(App.tsx)上:
// in the client side usually the root component, or in my case _app.tsx:
import electron from 'electron'
const ipcRenderer = electron.ipcRenderer
class _app extends React.Component<any, any> {
constructor(props: any) {
super(props)
// I put this since I use class based component.
// a functional ones won't need this
this.handleIpc = this.handleIpc.bind(this)
}
componentDidMount() {
this.handleIpc() // to make sure the ipcRenderer manipulate the component state AFTER the whole component was loaded first
}
handleIpc() {
var self = this
ipcRenderer.on("some-event", function (e, data) {
console.log("Message received: ", data)
})
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.