Now that we've explored how to send messages from the main process to the renderer process, let's shift our focus to the other side of the communication channel: receiving these messages in the renderer process. This is crucial for your renderer process to react to events or data originating from the main process, enabling dynamic and responsive user interfaces.
The primary mechanism for the renderer process to listen for messages from the main process is through the ipcRenderer module. Specifically, we'll be using the on() method. This method allows you to register a callback function that will be executed whenever a specific IPC event is emitted from the main process.
const { ipcRenderer } = require('electron');
ipcRenderer.on('your-channel-name', (event, ...args) => {
console.log('Message received from main process:', args);
// Update your UI here based on the message
});Let's break down the ipcRenderer.on() call:
'your-channel-name': This is a string that must exactly match the channel name used when the main process sent the message usingwebContents.send(). It acts as the identifier for the specific type of message you're expecting.(event, ...args): This is the callback function that gets executed when a message arrives on'your-channel-name'.event: The first argument is anIpcRendererEventobject. While it contains useful information, in many basic scenarios, you might not need to directly interact with it....args: This is a rest parameter that captures any additional arguments sent from the main process. If the main process sent multiple pieces of data, they will all be available here.
Consider a scenario where the main process sends a list of files to be displayed in the renderer. The main process might send this data like so:
// In your main process (e.g., main.js)
const { BrowserWindow, ipcMain } = require('electron');
let mainWindow;
function createWindow () {
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js') // Assuming you have a preload script
}
});
mainWindow.loadFile('index.html');
// Example: Send file list after a delay
setTimeout(() => {
const fileList = ['file1.txt', 'image.png', 'document.pdf'];
mainWindow.webContents.send('file-list', fileList);
}, 2000);
}
// ... other main process codeAnd in your renderer process (or more commonly, within your preload.js script if using context isolation), you would listen for this message:
// In your preload.js or renderer process script
const { ipcRenderer } = require('electron');
ipcRenderer.on('file-list', (event, files) => {
console.log('Received file list:', files);
const fileListElement = document.getElementById('file-list-display'); // Assuming you have an element with this ID
if (fileListElement) {
fileListElement.innerHTML = '<ul>' + files.map(file => `<li>${file}</li>`).join('') + '</ul>';
}
});It's good practice to remove listeners when they are no longer needed to prevent memory leaks. You can do this using ipcRenderer.removeListener() or ipcRenderer.removeAllListeners().
const fileListListener = (event, files) => {
console.log('Received file list:', files);
// ... update UI ...
};
ipcRenderer.on('file-list', fileListListener);
// Later, to remove the listener:
ipcRenderer.removeListener('file-list', fileListListener);The ipcRenderer.once() method is a convenient alternative when you only need to receive a message one time. After the listener is triggered, it's automatically removed.
ipcRenderer.once('single-message', (event, data) => {
console.log('This will only be logged once:', data);
});sequenceDiagram
participant Main Process
participant Renderer Process
Main Process->>Renderer Process: ipcRenderer.send('your-channel', data)
Renderer Process->>Renderer Process: ipcRenderer.on('your-channel', callback)
Renderer Process->>Renderer Process: callback(event, data)
Renderer Process->>Renderer Process: Update UI based on data