In the previous section, we learned how to send messages from the renderer process to the main process. Now, let's explore how the main process receives and handles these incoming messages. This is a crucial part of building interactive Electron applications, allowing your backend logic to react to user actions or data changes originating from the user interface.
The ipcMain module in Electron is your gateway to handling inter-process communication events originating from the renderer. Specifically, the ipcMain.on() method is used to register listeners for specific 'channels'. When a message is sent from a renderer process using ipcRenderer.send(), it travels along a named channel. The ipcMain.on() listener in the main process will be invoked if its registered channel matches the one used in the renderer.
const { ipcMain } = require('electron');
ipcMain.on('my-channel', (event, arg) => {
console.log('Message received in main process:', arg);
});Let's break down the ipcMain.on() syntax:
'my-channel': This is the name of the channel. It's a string that acts as an identifier for the communication. It must match the channel name used inipcRenderer.send()from the renderer process.(event, arg) => { ... }: This is the callback function that gets executed when a message is received on 'my-channel'.event: TheIpcMainEventobject provides information about the event, including thesenderproperty, which refers to the WebContents object that sent the message. This can be useful for sending a reply back to a specific renderer.arg: This represents the data payload sent from the renderer process. It can be any serializable JavaScript object (strings, numbers, arrays, objects, etc.).
Consider a scenario where you have a button in your renderer process that, when clicked, sends a user's input to the main process for validation. Here's how you might set up the listener in your main.js file:
// main.js
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
enableRemoteModule: false
}
});
mainWindow.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow();
ipcMain.on('validate-input', (event, userInput) => {
console.log(`Validating input: ${userInput}`);
// Perform validation logic here
const isValid = userInput.length > 3;
// You can send a response back to the renderer if needed (covered in next section)
event.sender.send('validation-result', isValid);
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});