Tengo un botón en mi aplicación de reacción que necesita hacer algo 1 vez cada vez que se hace clic. Actualmente, cuando se hace clic, el oyente parece multiplicarse.
Aquí hay un breve ejemplo del código que estoy usando:
// In App.js const App = () => { const buttonHandler = () => { api.myApi.rendererToMain(); api.myApi.mainToRenderer(); }; return ( <div> <Button cb={buttonHandler} /> </div> ); }; // In Button.js const Button = (props) => { return ( <button type="button" onClick={ (e) => { props.cb() }}>Send Ping</button> ) }; // In main.js ipcMain.on('async', (e, msg) => { console.log(msg); // print ping e.reply('async_response', 'pong'); }); // In preload.js contextBridge.exposeInMainWorld('api', { myApi: { rendererToMain: () => { ipcRenderer.send('async', 'ping'); }, mainToRenderer: () => { ipcRenderer.on('async_response', (e, msg) => { console.log(msg); }); }, }, });Cuando ejecuto la aplicación electrónica, tengo un terminal para el proceso principal abierto y devTools abierto para la salida del renderizador. Actualmente, cuando se presiona el botón 3 veces, el resultado se ve así:
// In the browserWindow devTools console pong (2)pong (5)pong // In the Main process console ping ping pingLa salida deseada solo es diferente para la consola del renderizador:
pong pong pongMi intento de solución
Mi primer intento de resolver esto por mi cuenta, después de algunas investigaciones de stackoverflow, fue intentar eliminar el oyente ipcRenderer para el canal "async_response". Todos los intentos de hacer esto resultaron en ningún resultado en la consola del renderizador y los 3 pings esperados en la consola del proceso principal.
Por ejemplo:
// Change made in preload.js contextBridge.exposeInMainWorld('api', { myApi: { rendererToMain: () => { ipcRenderer.send('async', 'ping'); }, mainToRenderer: () => { ipcRenderer.on('async_response', (e, msg) => { console.log(msg); // With below change, this does nothing. }); // Attempt to remove the listener now? // Seems to remove the listener before any output logged. ipcRenderer.removeAllListeners('async_response'); }, }, });Si alguien pudiera ayudarme a entender dónde y cómo evitar que los oyentes se multipliquen, se lo agradecería eternamente. Gracias de antemano.
Después de dormir un poco, me di cuenta de que mi búsqueda era demasiado estrecha. Descubrí que el método ipcRenderer.on() se estaba suscribiendo una vez más cada vez que se presionaba el botón, según los conceptos de esta publicación: Método Node .on disparando demasiadas veces
Al comprender esto, hice el siguiente cambio en mi código, de modo que la llamada al método ipcRenderer.on() solo ocurrió una vez:
// In App.js const App = () => { const buttonHandler = () => { api.myApi.rendererToMain(); // api.myApi.mainToRenderer(); <- Removed this call to the ipcRenderer.on() }; return ( <div> <Button cb={buttonHandler} /> </div> ); }; // In Button.js const Button = (props) => { const callbackHandler = () => { props.cb(); }; // Subscribe to listener on component construction api.myApi.mainToRenderer(); return ( <button type="button" onClick={ (e) => { callbackHandler() }}>Send Ping</button> ) };Estos cambios dan como resultado exactamente el comportamiento esperado. Después de tres clics en el botón, veo en la consola del renderizador:
(3)pongVoy a dejar esto sin respuesta por un tiempo. Definitivamente estoy abierto a comentarios sobre mi solución e implementación en general.