yourfavorite yourfavorite - 3 months ago 60
React JSX Question

Workaround for passing function to ipcMain and back using React, Redux, Electron

I am trying to load/update data from a local database file at certain times in my application. This file of course must be accessed from the main process, so I send to the main process from renderer and then when the main process returns the data I need, I need to run Redux's dispatch to update my state accordingly. The problem is that my ipcRenderer.on() listener doesn't have context to call dispatch properly. I tried passing a function through to the main process and then back to the renderer, but functions get stripped from ipcRenderer.send.

How can I properly update my state once I receive the data back from the main process? Below isolated chunks of my code.

Main process:

ipcMain.on('getSites', (event, args) => {
db.sites.find({}, (err, docs) => {
event.sender.send('getSitesSuccess', { data: docs, dispatch: args.dispatch });
});
});


Renderer process:

ipcRenderer.on('getSitesSuccess', (event, args) => {
args.dispatch(args.data);
});

class SiteList extends Component {
componentWillMount() {
ipcRenderer.send('getSites', {
test: 'test',
dispatch: (data) => { this.props.dispatch(actions.change('sites', data)); }
});
}
}

Answer

Make sure you set up your event listeners inside your class instance (componentDidMount). Also, make sure to properly dispose any event listeners once the instance disposes (componentWillUnmount).

class SiteList extends Component {
  componentDidMount() {
    ipcRenderer.on('getSitesSuccess', this.handleSitesSuccess);
  }

  componentWillUnmount() {
    ipcRenderer.removeListener('getSitesSuccess', handleSitesSuccess);
  }

  handleSitesSuccess(event, args) {
    console.log('data', args.data);
    props.dispatch(actions.change('sites', args.data));
  }
}

If you are doing a lot of ipc calls (both receive and send), have a look at redux-electron-ipc (link). This removes the wiring logic for ipc calls from your actual components and lets you work directly with redux state.

Note: I am the author of this plugin.