如何防止 ipcRenderer 监听器的倍增?

How to prevent multiplication of ipcRenderer listenters?

我的 React 应用程序中有一个按钮,每次单击它都需要执行 1 次操作。目前,当点击时,听者似乎成倍增加。

这是我使用的代码的简短示例:

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

当我 运行 电子应用程序时,我有一个主进程的终端打开,并且 devTools 打开用于渲染器的输出。目前,当按钮被按下 3 次时,结果如下:

// In the browserWindow devTools console
pong
(2)pong
(5)pong

// In the Main process console
ping
ping
ping

所需的输出仅与渲染器控制台不同:

pong
pong
pong

我尝试的解决方案

在对 Whosebug 进行一些研究之后,我第一次尝试自己解决这个问题是尝试删除“async_response”频道的 ipcRenderer 侦听器。执行此操作的所有尝试都导致渲染器控制台中没有输出,并且主进程控制台中的所有 3 个预期 ping。

例如:

// 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');
        },
    },
});

如果有人能帮助我了解在哪里以及如何阻止听众的增加,我将永远感激不已。提前谢谢你。

睡了一觉后,我意识到我的搜索范围太窄了。我发现每次按下按钮时都会额外订阅 ipcRenderer.on() 方法,根据此 post 中的概念:

了解这一点后,我对代码进行了以下更改,以便对 ipcRenderer.on() 方法的调用仅发生一次:

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

这些更改会导致完全符合预期的行为。单击按钮三下后,我在渲染器控制台中看到:

(3)pong

暂时不回答这个问题。我绝对愿意接受有关我的修复和实施的评论。