reactjs - contextBridge.exposeInMainWorld en preload.ts: ipcRenderer recibe el mensaje de main.ts pero el renderer no lo recibe
Dentro de una aplicación Electron-React-TypeScript, logré enviar un mensaje desde el proceso renderer al main a través de contextBridge.exposeInMainWorld en preload, pero en el camino de regreso, la salida procesada desde el main, en realidad pasa y llega a preload.ts, pero no llega al proceso renderer. Debe ser algo realmente "estúpido", pero no sé quién es el "culpable". Así que, te pido tu amable ayuda.
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);
});
}
});
Proceso del renderizador (¡donde los datos no se muestran correctamente!) :
visorDemo.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;
En main obtengo: path recibido desde main: ./images/natural-scene.jpeg mientras que para el camino de regreso de main a renderer obtengo: No se puede leer la propiedad '0' de undefined
Si en contextBridge.exposeInMainWorld en la parte 'receive' de la API pongo:
receive: (channel, func) => {
//ipcRenderer.on(channel, (event, ...args) => func(...args))
ipcRenderer.on(channel, (event, ...args) => {
console.log("ipcRenderer.on-args: ", args);
});
}
Ya no recibo ese error, dentro de preload.ts aparece el mensaje correcto de main.ts, pero el proceso de renderer aún no lo recibe:
Respuesta #1
Probablemente ya hayas encontrado la respuesta a esto, pero por si acaso y en beneficio de cualquiera que se encuentre con esta pregunta; aunque no he podido ejecutar el código para demostrar que este es el problema, creo que es un problema con la función de recepción de precarga:
El método proxy ipcRenderer.on llama a tu manejador "func" solo con la dispersión de los parámetros args. Pero en viewerDemo.tsx, el método manejador que pasas a "receive" para ser llamado como "func" espera dos parámetros: "event" y "args". En consecuencia, tu parámetro único pasado en args probablemente está apareciendo como un arreglo de un solo elemento en el parámetro "event".
Para probar la teoría y, con suerte, arreglar esto, haz que los métodos sean consistentes. Podrías cambiar esta línea en tu manejador en viewerDemo.tsx de
window.api.receive("path-to-url", (event, args) => {
a
window.api.receive("path-to-url", (args) => {
O en preload.ts cambia esta línea
ipcRenderer.on(channel, (event, ...args) => func(...args))
por
ipcRenderer.on(channel, (event, ...args) => func(event, ...args))
Cualquiera debería solucionar el problema.

