【问题标题】:Remove event listener from `preload.js` in Electron created by React component从 React 组件创建的 Electron 中的 preload.js 中删除事件监听器
【发布时间】:2021-10-26 14:55:57
【问题描述】:

我将 Electron 13 与 React 17 一起使用。我已将 nodeIntegration 设置为 false 并将 contextIsolation 设置为 true,因此我使用 preload.js 文件来公开 API 以在主进程和渲染器进程之间进行通信。

我必须使用这个 API 在 React 组件中监听 IPC 消息。但是,每次我的组件被挂载(或重新渲染)时,Electron 都会创建一个新的 IPC 事件侦听器,从而导致内存泄漏。

preload.js

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('api', {
    send: (channel, data) => {
        // Whitelist channels
        let validChannels = ['toMain'];
        if (validChannels.includes(channel)) {
            ipcRenderer.send(channel, data);
        }
    },
    receive: (channel, func) => {
        let validChannels = ['fromMain'];
        if (validChannels.includes(channel)) {
            // Deliberately strip event as it includes `sender`
            ipcRenderer.on(channel, (event, ...args) => func(...args));
        }
    }
});

ReactComponent.js

import { useEffect, useRef } from 'react';

const ReactComponent = () => {
    const _isMounted = useRef(true);

    const exampleFunction = () => {
        window.api.send('toMain');
    };

    window.api.receive('fromMain', function (data) {
        if (_isMounted.current) {
            // Process `data`...
        }
    });

    useEffect(() => {
        exampleFunction();

        // Another IPC call
        window.api.send('toMain', ['example']);
        window.api.receive('fromMain', function (data) {
            // Process `data`...
        });

        return () => {
            _isMounted.current = false;
            // Somehow I should remove the IPC event listeners here,
            // but I don't know how, since (I think) they are created 
            // in the `preload.js` file...
        };
    }, []);


    return (
        // JSX
    );
};

export default ReactComponent;

如何取消注册通过window.api.receive() 创建的事件监听器?

【问题讨论】:

    标签: reactjs events electron ipc


    【解决方案1】:

    This issue on GitHub 正好解决了这些问题。简而言之,将preload.js 中创建的事件监听器分配给一个变量,以便脚本可以返回一个回调来移除事件监听器。

    这是一个如何执行的示例:

    preload.js

    const { contextBridge, ipcRenderer } = require('electron');
    
    contextBridge.exposeInMainWorld('api', {
        // ...
        receive: (channel, func) => {
            let validChannels = ['fromMain'];
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender`
                const subscription = (event, ...args) => func(...args);
                ipcRenderer.on(channel, subscription);
                return () => {
                    ipcRenderer.removeListener(channel, subscription);
                };
            }
        },
    });
    

    ReactComponent.js

    import { useEffect } from 'react';
    
    const ReactComponent = () => {
    
        const onEvent = (data) => {
            // Process `data`...
        };
    
        useEffect(() => {
            const removeEventListener = window.api.receive('fromMain', (data) => onEvent(data));
    
            // ...
    
            return () => {
                removeEventListener();
            };
        }, []);
    
        return (
            // JSX
        ); 
    };
    
    export default ReactComponent;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-15
      • 1970-01-01
      • 2014-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多