网站搜索

reactjs - 在 preload.ts 中使用 contextBridge.exposeInMainWorld:ipcRenderer 接收到来自 main.ts 的消息,但渲染进程没有收到


在一个 Electron-React-Typescript 应用中,我设法通过 preload 中的 contextBridge.exposeInMainWorld 从渲染进程向主进程发送消息,但在返回的过程中,从主进程处理后的输出实际上确实传回并到达了 preload.ts,但它没有到达渲染进程。这一定是某个非常“愚蠢”的问题,但我不知道问题的“罪魁祸首”是什么。所以,我请求你提供帮助。

preload.ts :

const {
  contextBridge,
  ipcRenderer
} = require("electron")


contextBridge.exposeInMainWorld(
  "api", {
      send: (channel, data) => {
          ipcRenderer.invoke(channel, data).catch(e => console.log(e))
      },
      receive: (channel, func) => {
        ipcRenderer.on(channel, (event, ...args) => func(...args))
        //ipcRenderer.on(channel, (event, ...args) => {
          //console.log("ipcRenderer.on-args: ", args);
        //});
      }
)

index.d.ts :

declare interface Window {
    api: {
      send: (channel: string, ...arg: any) => void;
      receive: (channel: string, func: (event: any, ...arg: any) => void) => void;
    }
}

main.ts :

ipcMain.handle("path-to-url", (IpcMainEvent, path) => {
  console.log("received a request from viewerDemo");
  if (mainWindow) {
    let urlified = url.pathToFileURL(path);
    console.log("urlified = url.pathToFileURL(path) : ", urlified);
    console.log("urlified.href= ", urlified.href);
    console.log("urlified.pathname= ", url.pathToFileURL(path).pathname);
    mainWindow.webContents.on("dom-ready", () => {
      mainWindow.webContents.send("path-to-url", "ohhhhhhhhhhhhhhhh");
      mainWindow.webContents.send("path-to-url", url.pathToFileURL(path).pathname);
    });
  }
});

渲染进程(数据显示不正常的地方!) :

viewerDemo.tsx

import * as React from 'react';
import Viewer from 'react-viewer';

let path_1 = './images/natural-scene.jpeg';
let url_path;

const pathToUrlFunc = (path): string => {
  console.log("pathToUrlFunc called");
  window.api.send("path-to-url", path);
  let urlPath;
  window.api.receive("path-to-url", (event, args) => {
    console.log("window.api.receive called!");
    console.log("window.api.receive-args[0]: ", args[0]);
    urlPath = args[0];
  });
  return urlPath;
}

function ViewerDemo() {
  const [ visible, setVisible ] = React.useState(false);

  let urlpath = pathToUrlFunc(path_1);
  console.log("urlpath: ", urlpath);

  return (
    <div>
      <button onClick={() => { setVisible(true); } }>show</button>
      <Viewer
      visible={visible}
      onClose={() => { setVisible(false); } }
      images={[{src: 'https://www.fotolip.com/wp-content/uploads/2016/05/Nature-Scenes-
21.jpg', alt: ''}]}
      //images={[{src: urlpath, alt: ''}]}

      />
    </div>
  );
}

export default ViewerDemo;

在 main 中我得到:path received from main: ./images/natural-scene.jpeg,而从 main 返回到 renderer 的方式我得到:Cannot read property '0' of undefined

如果在 api 的 'receive' 部分的 contextBridge.exposeInMainWorld 中我写:

  receive: (channel, func) => {
    //ipcRenderer.on(channel, (event, ...args) => func(...args))
    ipcRenderer.on(channel, (event, ...args) => {
      console.log("ipcRenderer.on-args: ", args);
    });
  }

我不再遇到那个错误,在 preload.ts 中,来自 main.ts 的正确消息出现了,但渲染进程仍然没有收到它:

答案#1

你现在可能已经找到了这个问题的答案,但以防万一以及为了帮助可能碰到这个问题的人;虽然我还没有能够运行代码来证明这是问题所在,但我认为问题出在预加载接收函数上:

ipcRenderer.on 代理方法仅使用 args 参数的展开来调用你的“func”处理程序。但在 viewerDemo.tsx 中,你传递给“receive”以作为“func”调用的处理方法期望两个参数“event”和“args”。因此,你在 args 中传递的单个参数可能会作为单元素数组出现在“event”参数中。

为了测试这个理论并希望能解决这个问题,使方法保持一致。你可以在 viewerDemo.tsx 中的处理程序里将这一行修改为

window.api.receive("path-to-url", (event, args) => {
变为
window.api.receive("path-to-url", (args) => {

或者在 preload.ts 中更改这一行
ipcRenderer.on(channel, (event, ...args) => func(...args))
为
ipcRenderer.on(channel, (event, ...args) => func(event, ...args))

任何一个都应该可以解决问题。