Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Electron: Change React component state from main.js

I have an Electron app with include (among others) the following files:

  • index.js
  • browserwindow.html
  • browserwindow.js (which get compiled from browserwindow.jsx)

index.js is the main Electron/Node process that runs when the Electron app is started. browserwindow.html is rendered in the guiWindow, browserwindow.js manages this window. (See the files below.)

What I want, is to send an ipc message from the main Electron proccess to browserwindow.js, which then updates the React component state. But when I use the code in the files below and run the Electron app, the state does not change.

index.js

const electron = require('electron');
const BrowserWindow = electron.BrowserWindow;
const app = electron.app;
const url = require('url');
const ipc = electron.ipcMain;


app.on('ready', function(){

  // Make window
  var guiWindow;

  // Set size and do not immediately show
  guiWindow = new BrowserWindow({
    width: 800,
    height: 780,
    show: false
  });

  // Load browserwindow.html in the guiWindow
  guiWindow.loadURL('file://' + __dirname + '/browserwindow.html');

  // Show the window when the .html file is loaded
  guiWindow.once('ready-to-show', function(){
    guiWindow.show();
  });

  // Send an ipc after 3 seconds
  setInterval(function(){
    guiWindow.webContents.send('message', {msg: 'Hello World!'});
  }, 3000);

});

browserwindow.html

<!DOCTYPE html>
<html>
  <head>
    <title>Page</title>
  </head>
  <body>
    <!-- The div that React uses: -->
    <div id="mainInterface"></div>
    <script src="react-0.14.3.js"></script>
    <script src="react-dom-0.14.3.js"></script>
    <script src="browserwindow.js"></script>
  </body>
</html>

jsx that gets compiled to browserwindow.js

var electron = require('electron');
var shell = electron.shell;
var ipc = electron.ipcRenderer;

class MainInterface extends React.Component {

  constructor(props, contect){
    super(props);
    this.state = {
      testValue: 'Initial state'
    };
  };

  componentDidMount(){ // When the document is rendered

    ipc.on('message', function(event, data){ // When the message is received...
      console.log('Message received');
      this.setState({testValue: 'It worked!'}); // ... change the state of this React component
    });

  }

  render(){
    return (
      <h1>{ this.state.testValue }</h1>
    );
  }

}

ReactDOM.render(
  <MainInterface />,
  document.getElementById('mainInterface')
);

In the Javascript console, I get the following error:

Uncaught TypeError: this.setState is not a function
    at EventEmitter.<anonymous> (file:///C:/Users/<file path to the project on my computer>/testproject/browserwindow.js:20:12)
    at emitTwo (events.js:106:13)
    at EventEmitter.emit (events.js:194:7)

What can I do to fix this issue?

(For some background, I am making an Electron app that should receives messages over MQTT and update the elements on the screen based on the received message.)

like image 313
Kevin Avatar asked Sep 18 '25 12:09

Kevin


1 Answers

Your this points to the different context than component really is. You need to change your code to

componentDidMount() {
    // When the document is rendered.
    const self = this;
    ipc.on('message', function (event, data) {
        // When the message is received...
        console.log('Message received');
        // ... change the state of this React component.
        self.setState({testValue: 'It worked!'});
    });
}

Or you may replace function() callback by () => {} because the first option changes the context of the execution.

like image 149
Dominis Avatar answered Sep 20 '25 02:09

Dominis