signal from Main to Renderer not reaching contextBridge?

76 Views Asked by At

When the app is launched, I am trying to send some data from main.js to renderer.js so that renderer.js can begin rendering some elements. I have no idea what is going wrong, but it seems communication breaks down at preload.js. I have checked Electron's documentation and my code looks fine. I have no problem communicating from renderer.js to main.js to renderer.js, but communicating from main.js to renderer.js does not want to work. Any help would be very much appreciated.

As per @elichen's instruction, I tested ipcRenderer.on('data:dataList',()=>console.log('called')) at the top of preload.js and this is logging... What the heck is going on here?

// main.js

async function readJSON(filePath) {
  try {
    const data = await fs.readFile(filePath, 'utf-8')
    return JSON.parse(data)
  } catch (error) {
    if (error.code === 'ENOENT') return []
    else throw error
  }
}

async function loadData() {
  try {
    const
      configFilePath = path.join(app.getPath('userData'), 'List of Data Points.json'),
      dataList = await readJSON(configFilePath)
    if (dataList.length) {
      console.log(dataList.length) //## THIS LOGS CORRECTLY ##//
      mainWindow.webContents.send('data:dataList', dataList)
      console.log('Sent data from main.js') //## THIS LOGS TO MAIN.JS CONSOLE ##//
    }
  } catch (error) {
    console.error('Error reading configuration file:', error)
  }
}

app.whenReady().then(()=>{
  createWindow()
  loadData()
  ...
// preload.js

ipcRenderer.on('data:dataList',()=>console.log('called')) //## THIS LOGS ##//

contextBridge.exposeInMainWorld('myAPI',
  {
    onDataListReady: (callback) => ipcRenderer.on('data:dataList', (_event, value) => {
      console.log('Why does this not work?') //## THIS DOES NOT LOG ##//
      return callback(value)
    }),
    ...
// renderer.js

window.myAPI.onDataListReady((value) => {
  console.log(value) //## THIS DOES NOT LOG TO BROWSER CONSOLE ##//
  try {
    dataList.forEach(it=>console.log(it))
  } catch (error) {
    console.error('Error in onDataListReady:', error)
  }
})
1

There are 1 best solutions below

0
eli chen On BEST ANSWER

the reason ipcRenderer.on('data:dataList',... not called is because the order of things

  1. createWindow() at this step the preload is loading but the listener for data:dataList not yet created. (its created by calling onDataListReady which calls later)

  2. loadData() at this step the main send to preload the event but no one listening to that event

  3. the render called onDataListReady which only now create the listener.

the fix to that problem is normally subject to implementation of the app. a small fix can be by calling loadData after all dom and js loaded for example using did-finish-load event like below

createWindow(){
...
mywin.webContents.on('did-finish-load',()=>loadData())
...
}