So I'm pretty new to Electron, and my goal is to have a completely offline application that effectively queries and displays results from a loaded SQLite file (hence the questionable SQL practices here).
I am able to query my database and get expected returns. However, when I make consecutive calls like this, the second query is getting the same result as the previous call. Here is the bit from my renderer (React). The first query will usually as expected, but then the second res is identical to that of the first. However, sometimes the second query gets the expected result and the first is identical to that. Either way, they both end up with the same res value.
Any ideas on what exactly is happening and how I can fix this? I don't believe a synchronous approach would be possible with ipcMain.
Code in renderer (React)
// called from ipcMain when database file is set
ipcRenderer.on('set-db', (event, arg) => {
// Get authors
queryDB("SELECT * FROM users;")
.then((res) => {
try {
var options = [];
res.forEach((e) => {
options.push({value: e.id, label: `@${e.name}`});
if (e.display_name != e.name) {
options.push({value: e.id, label: `@${e.display_name}`});
}
});
setAuthorOptions(options);
console.log("Set author options");
}
catch (exception) {}
});
// Get channels
queryDB("SELECT * FROM channels;")
.then((res) => {
try {
var options = [];
res.forEach((e) => {
if (allowedChannelTypes.includes(e.type)) {
options.push({value: e.id, label: `# ${e.name}`});
}
});
setChannelOptions(options);
console.log("Set channel options");
}
catch (exception) {}
});
});
Here is the code in the main process
ipcMain.on('asynchronous-message', (event, sql) => {
if (db) {
db.all(sql, (error, rows) => {
event.reply('asynchronous-reply', (error && error.message) || rows);
});
}
return
});
And the renderer code
export default function queryDB(sql) {
return new Promise((res) => {
ipcRenderer.once('asynchronous-reply', (_, arg) => {
res(arg);
});
ipcRenderer.send('asynchronous-message', sql);
})
}
The problem is that you are using
ipcRenderer.onceseveral times with the same channel name. As described in the docs, this method:So if you make a new call before the previous one got a reply, they will both receive the results of the first one which is answered.
I'm not familiar with SQLite, but from what I gathered, depending on the library you use
db.all()will either work with a callback or be a promise. I see two ways to fix this:With a promise
If you use the promise way, you can simply use
invoke/handle. For example:Renderer
Main
With a callback
If you prefer to use a callback, you have to make sure that you use unique channel names with
ipcRenderer.once, for example:Renderer
Main
If you use this method, and since you don't always send a reply to the created channel, you also need to make sure you cleanup the unused listeners using ipcRenderer.removeListener or ipcRenderer.removeAllListeners.