【问题标题】:How to implement websocket client in Electron (Next.js/React)?如何在 Electron (Next.js/React) 中实现 websocket 客户端?
【发布时间】:2022-12-19 18:06:56
【问题描述】:

我有一个工作的 websocket 服务器。我以前在网络浏览器/反应中使用 websocket 作为客户端,但我无法在电子应用程序中使用 Websocket,因为 WebSocket 取决于浏览器的兼容性,并且出于某种原因,此功能在 Electron 中不可用。

I use nextron (nextjs/react + electron) boilerplate.

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>
  );
}

【问题讨论】:

    标签: javascript reactjs websocket electron


    【解决方案1】:

    显然是做不到的。 Electron 阻止任何在客户端 (React) 内使用 websocket 的尝试。到目前为止我使用的唯一解决方案是将 websocket 消息和事件转换为 ipcRenderer(https://www.electronjs.org/docs/latest/api/ipc-renderer)

    这个过程相当简单: React 收到一个事件并调用客户端上的 IPCRenderer,IPCRenderer 在渲染器(node.js)中接收一个事件并调用 ws 或 node.js 中的 websocket

    发送:

    React -> IPC -> Node.js -> websocket -> Websocket Server (main server) 
    

    接收:

    Websocket Server (main server) -> websocket -> Node.js -> IPC -> React
    

    我使用来自here的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)
        })
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2014-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-02
      • 1970-01-01
      • 2020-03-05
      相关资源
      最近更新 更多