Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Electron - communicate to renderer on window show

I'm trying to capture an event in my renderer process (react application) when the electron window is shown in my main.js. I'm unable (to my knowledge) to use the react component lifecycle because the component already mounts on initial load and doesn't update unless state changes, which the electron main process, ShowWindow, triggers neither after initial load.

My use case is to check for new data when the user opens the window from the tray, and trigger a notification. Again, booting the application, closing the tray, and then reopening does not update the state thus prevents me from utilizing the component lifecycle.

So, I'm trying to find a way to send a message from ipcMain to ipcRenderer when the main process shows the window, but am having issues figure out how.

Here's the relevant main.js code:

tray.on('click', function (event) {
   toggleWindow()
}

function toggleWindow() {
  if (window.isVisible()) {
   window.hide()
  } else {
   showWindow()
  }
}

function showWindow() {
  const position = getWindowPosition()
  window.setPosition(position.x, position.y, false)
  window.show()
  window.focus()
  toggleTrayIcon()
}

Elsewhere in my code, I'm doing something like this to communicate back to the renderer, but in this case, I'm unsure of how to handle the event object:

ipcMain.on('open-finder', function(event, arg) {
  let properties = { properties: ['openFile'], filters: [{name: 'Images', extensions: ['jpg', 'png', 'jpeg']}] }
  let filePath = dialog.showOpenDialog(window, properties);
  let fileData = filePath ? getBase64(filePath[0]) : null
  event.sender.send('open-finder-reply', fileData);
});

and then in my react component I want to do something like so (related to above example) to handle that event and trigger my notification:

class Profile extends Component {
  constructor(props) {
  super(props)

  ipcRenderer.on('open-finder-reply', (event, fileData) => {
    this.props.updateAvatar(fileData)
  });
}

I might be going about this all wrong. Relatively new to Electron. Any help at all would be greatly appreciated. Thank you!

like image 316
jmtibs Avatar asked Jan 30 '23 08:01

jmtibs


1 Answers

A full example for communication between main and renderer's react component could be something like the following.

For sending ipc message to renderer you can use webContents.send

main.js

const { app, BrowserWindow } = require('electron')
const path = require('path')

app.once('ready', () => {
  const win = new BrowserWindow()
  win.webContents.once('dom-ready', () => {
    setTimeout(() => {
      win.webContents.send('ready') // send to renderer
    }, 3000)
  })
  win.loadURL(path.join(__dirname, 'renderer.html'))
})

renderer.html

<html>
  <head>
    <script src="./renderer.js" charset="utf-8"></script>
  </head>
  <body>
    <div id="render"></div>
  </body>
</html>

renderer.js

const React = require('react')
const ReactDOM = require('react-dom')
require('babel-register')

const Comp = require('./component')

window.onload = () => {
  ReactDOM.render(
    React.createElement(Comp),
    document.getElementById('render')
  )
}

component.js

const { ipcRenderer } = require('electron')
const React = require('react')

module.exports = class extends React.Component {
  constructor (props) {
    super(props)
    this.state = {isReady: false}
    ipcRenderer.on('ready', () => {
      this.setState({isReady: true})
    })
  }
  render () {
    return <p>Is ready: {`${this.state.isReady}`}</p>
  }
}
like image 104
pergy Avatar answered Feb 05 '23 18:02

pergy