简体   繁体   English

在电子反应应用程序中多次触发 NodeJS 事件

[英]NodeJS events triggering multiple times in electron-react app

I have a package (Let's say PACKAGE_A ) written to do some tasks.我有一个 package (比方说PACKAGE_A )写来做一些任务。 Then it is required by PACKAGE_B .然后PACKAGE_B需要它。 PACKAGE_A is a node script for some automation work. PACKAGE_A是一些自动化工作的节点脚本。 It has this Notifier module to create and export an EventEmitter.它有这个 Notifier 模块来创建和导出 EventEmitter。 (The Whole project is a Monorepo) (整个项目是一个 Monorepo)

const EventEmitter = require('events');

let myNotifier = new EventEmitter();

module.exports = myNotifier;

So in some functions in PACKAGE_A it emits event by requiring myNotifier , and also in the index.js of PACKAGE_A , I export functions (API exposed to the other packages) and the myNotifier by requiring it again.因此,在PACKAGE_A中的某些函数中,它通过要求myNotifier发出事件,并且在PACKAGE_Aindex.js中,我通过再次要求它来导出函数(暴露给其他包的 API)和myNotifier

const myNotifier = require('./myNotifier);

const func1 = () => {
    // some function
    return something;
}

module.exports = {func1, myNotifier}

Then I import the PACKAGE_A in PACKAGE_B and use the API functions exposed with the notifier.然后我在PACKAGE_A中导入PACKAGE_B并使用通知程序公开的 API 函数。 PACKAGE_B is an electron app with a React UI. PACKAGE_B是一个带有 React UI 的 electron 应用程序。

Below is how the program works.以下是该程序的工作原理。

I have a console output window in the electron app (React UI, UI_A ).我在 electron 应用程序(React UI, UI_A )中有一个控制台 output window。 <= (keep this in mind) <=(记住这一点)

When I click a button in UI_A it fires a redux action ( button_action ).当我单击UI_A中的按钮时,它会触发redux 操作button_action )。 Inside the action, a notification is sent to an event which is listened in the electron code using ipcRenderer.在动作内部,使用 ipcRenderer 向在 electron 代码中侦听的事件发送通知。

ipcRenderer.send('button-clicked', data); // <= this is not the full code of the action. It's bellow.

Then in the electron code (index.js), I require another file ( UI_A_COM.js which houses the code related to UI_A in electron side).然后在 electron 代码(index.js)中,我需要另一个文件( UI_A_COM.js包含与electron端的 UI_A 相关的代码)。 The reason is code separation.原因是代码分离。 Here's part of the code in index.js related to the electron.这是index.js中与 electron 相关的部分代码。

const ui_a_com = require('./electron/UI_A_COM');

const createWindow = () => {
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true,
        },
        resizable: false,
    });
    mainWindow.loadURL('http://localhost:3000');
    const mainMenu = Menu.buildFromTemplate(menuTemplate);
    ui_a_com (mainWindow);
};

Alright.好吧。 Then in UI_A_COM.js , I listen to that triggered event button-clicked .然后在UI_A_COM.js中,我听那个触发的事件button-clicked

ipcMain.on('button-clicked', someFunction); ipcMain.on('按钮点击', someFunction);

which runs the code from PACKAGE_A and return a result.它从PACKAGE_A运行代码并返回结果。 So now when PACKAGE_A runs, it emits some events using myNotifier .所以现在当PACKAGE_A运行时,它会使用myNotifier发出一些事件。 I listen to them in the same file ( UI_A_COM.js ), and when those events are captured, I again send some events to React UI, which is subscribed when button_action fired.我在同一个文件 ( UI_A_COM.js ) 中收听它们,当这些事件被捕获时,我再次将一些事件发送到 React UI,当button_action触发时订阅。

myNotifier.on('pac_a_event_a', msg => {
    mainWindow.webContents.send('ui_event_a', msg); // code in `UI_A_COM.js`
});

Here's the full code for the action.这是该操作的完整代码。 (Did not provide earlier because you'll get confused) (之前没有提供,因为你会感到困惑)

export const buttonAction = runs => {
    return dispatch => {
        ipcRenderer.send('button-clicked', data);

        ipcRenderer.on('ui_event_a', (event, msg) => {
            dispatch({ type: SOME_TYPE, payload: { type: msg } });
        });

    };
};

This will show the msg in the UI_A console.这将在UI_A控制台中显示消息。

So this is the task I'm doing.这就是我正在做的任务。 The problem is when I click the button;问题是当我单击按钮时; it works perfectly for the first time.它第一次完美运行。 But when I click the button on the second time, it received two messages.但是当我第二次单击该按钮时,它收到了两条消息。 Then when I click the button again, three messages and it keeps growing.然后,当我再次单击该按钮时,会出现三条消息,并且它一直在增长。 (but the functions in the PACKAGE_A only executes one time per button press). (但 PACKAGE_A 中的函数每次按下按钮仅执行一次)。

Let's say the message from PACKAGE_A emitted is 'Hello there' per execution.假设每次执行时发出的PACKAGE_A发出的消息是“Hello there”。

When I press the button 1st time a perfect result => Hello there, When I click the button again => Hello there Hello there, When I click it again => Hello there Hello there Hello there.当我第一次按下按钮时,一个完美的结果 => 你好,当我再次点击按钮 => 你好,你好,当我再次点击它时 => 你好,你好,你好。

It's kept so on.一直这样。 I think my implementation of EventEmitter has some flows.我认为我的 EventEmitter 实现有一些流程。 So why it's happening like this?那么为什么会这样呢? Is it EventEmitter or something else?是 EventEmitter 还是别的什么? What am I doing wrong here?我在这里做错了什么?

I think you should return a function that call ipcRenderer.removeAllListeners() in your component's useEffect() .我认为您应该在组件的useEffect()返回一个调用ipcRenderer.removeAllListeners()的函数。 Because every time you click your custom button, the ipcRenderer.on(channel, listener) is called, so you set a listener to that channel agin and agin...因为每次单击自定义按钮时, ipcRenderer.on(channel, listener) ,因此您将侦听器设置为该频道 agin 和 agin...

Example:例子:

  useEffect(() => {
    electron.ipcRenderer.on('myChannel', (event, arg) => {
      dispatch({ type: arg });
    });
    return () => {
      electron.ipcRenderer.removeAllListeners('myChannel');
    };
  });

By default the electron-react boilerplate doesnt define the ipcRenderer.removeAllListeners method.默认情况下,电子反应样板没有定义ipcRenderer.removeAllListeners方法。 So you have to first go to the main/preloads.ts file and add them:所以你必须首先 go 到main/preloads.ts文件并添加它们:

removeListener(channel: string, func: (...args: unknown[]) => void) {
  ipcRenderer.removeListener(channel, (_event, ...args) => func(...args));
},
removeAllListeners(channel: string) {
  ipcRenderer.removeAllListeners(channel);
},

Then go to the renderer/preload.ts declaration file and add the declarations too:然后 go 到renderer/preload.ts声明文件并添加声明:

removeListener(
  channel: string,
  func: (...args: unknown[]) => void
): void;
removeAllListeners(channel: string): void;

After that make sure to clean all listeners in the cleanup function of your useEffects each time you listen to an event fired.之后,确保在每次收听触发的事件时清除 useEffects 的清理 function 中的所有侦听器。 This will prevent multiple firing.这将防止多次射击。

useEffect(() => {
  window.electron.ipcRenderer.on('myChannel', (event, arg) => {
    // do stuffs
  });
  return () => {
    window.electron.ipcRenderer.removeAllListeners('myChannel');
  };
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Websockets 在 React JS + Electron NodeJS 应用程序中多次连接 - Websockets connecting multiple times in React JS + Electron NodeJS application 使用 Jest 对 Electron-React 应用程序进行单元测试,TypeError:无法匹配“未定义”或“空” - Unit-testing Electron-React app with Jest, TypeError: Cannot match against 'undefined' or 'null' 在反应中多次触发去抖动 - Debounce triggering multiple times in react Nodejs事件触发多次 - Nodejs events firing multiple times Nodejs和webSockets是否触发事件? - Nodejs and webSockets, triggering events? nodejs事件被多次调用 - nodejs events is being called multiple times 我的视图中的Backbone.js事件被多次触发 - Backbone.js events in my views being triggering multiple times Windows.alert() 阻止访问/数据输入到电子反应应用程序中的文本输入字段。 处理 windows.alert 的最佳方法是什么? - Windows.alert() preventing access/data entry into text input field in electron-react app. What is the best way to handle windows.alert? 鼠标事件未触发反应 - Mouse events not triggering in react Electron-React:MaxListenersExceededWarning:检测到可能的 EventEmitter memory 泄漏。 21 个 updateDeviceList 监听器添加到 [EventEmitter] - Electron-React: MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 21 updateDeviceList listeners added to [EventEmitter]
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM