reactjs 无法从通过React组件添加的电子IPC中删除侦听器

5cnsuln7  于 2022-11-04  发布在  React
关注(0)|答案(1)|浏览(153)

我有一个简单的React组件,它在安装时在IPC中注册了一个新的侦听器,在卸载时应该删除该侦听器。问题是,由于某种原因,我的侦听器引用与注册它时使用的引用不匹配,我不知道为什么。

React组件简化代码

import React, { useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAppDispatch } from '../../redux/storeHooks';
import { setAuthToken } from './state/authSlice';

import { LocationAuthState } from '../common/RequireAuth/types';

export default () => {
    const dispatch = useAppDispatch();
    const navigate = useNavigate();
    const navigatedFrom = useNavigatedFrom();

    useEffect(() => {
        const userLoggedInHandler = (_: Electron.IpcRendererEvent, loginToken: string) => {
            dispatch(setAuthToken({ token: loginToken }));
            navigate(navigatedFrom, { replace: true });
        };

        const ref1 = userLoggedInHandler;

        window.ipc.startLoginListenerHttpServer();
        window.ipc.userLoggedIn(userLoggedInHandler);

        return () => {
            const theSame = ref1 === userLoggedInHandler;
            console.log(theSame); // this logs true

            window.ipc.stopLoginListenerHttpServer();
            window.ipc.removeUserLoggedInListener(userLoggedInHandler);
        };
    }, []);

    return (
        <div>
            {`Waiting for login result...`}
        </div>
    );
};

function useNavigatedFrom() {
    const location = useLocation();
    const locationState = location.state as LocationAuthState;
    return locationState?.from?.pathname || `/`;
}

预加载. js

import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
import IpcEvent from '../ipcEvent';

let originalHandlerReference: any;

contextBridge.exposeInMainWorld(`ipc`, {
    startLoginListenerHttpServer: () => ipcRenderer.send(IpcEvent.StartLoginListenerHttpServer),
    stopLoginListenerHttpServer: () => ipcRenderer.send(IpcEvent.StopLoginListenerHttpServer),

    userLoggedIn: (handler: (event: IpcRendererEvent, loginToken: string) => void) => {
        originalHandlerReference = handler;
        ipcRenderer.on(IpcEvent.UserLoggedIn, handler);
    },

    removeUserLoggedInListener: (handler: (event: IpcRendererEvent, loginToken: string) => void) => {
        const countBefore = ipcRenderer.listenerCount(IpcEvent.UserLoggedIn); // 1

        const theSame = originalHandlerReference === handler; // false

        const theSameAsOriginal = originalHandlerReference === ipcRenderer.listeners(IpcEvent.UserLoggedIn)[0]; // true
        const theSameAsCurrentHandler = handler === ipcRenderer.listeners(IpcEvent.UserLoggedIn)[0]; // false

        ipcRenderer.off(IpcEvent.UserLoggedIn, handler);

        const countAfter = ipcRenderer.listenerCount(IpcEvent.UserLoggedIn); // 1
    },
});
von4xj4u

von4xj4u1#

看看contextBridge上的电子文档,我们可以看到“正常”渲染器进程和执行预加载脚本的隔离部分之间的通信是双向 * 复制 * 的。这意味着在渲染器和预加载上下文之间传递的任何两个对象(反之亦然)都不会 * 完全 * 相同。
因此,您不能使用===来检查传递给预加载脚本的两个函数是否相等。我建议为每个注册的侦听器生成一个ID,将其传递给调用代码,并将其存储在实际函数旁边的Map中。这样,组件就可以调用您的“unmount”函数,提供注册其侦听器时提供的ID。预加载脚本将查找给定ID的处理程序函数并将其从IPC通道中移除。

相关问题