Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Minimal Example: Opening a window in electron from react application?

Say I am building a desktop application with react/redux & electron. So my index.html file in electron looks like this:

<!DOCTYPE html>
<html>
 ...
  <body>

    <div id="content"></div>

  <script src="public/js/bundle.js"></script>
  </body>
</html>

My biggest React container (call it app.js) is loaded into the 'id=content' div. This works fine so far, but now I am wondering how to open a new file dialog window (or any new window for that matter) when the user clicks a button in my react application.

I found some examples here & here, but both examples only explain how to load the file dialog window from the main electron processes (in renderer or main).

However, I want the user to engage with my React Application and then, once he or she clicks a button, my app should then tell electron to spawn a new window, and this new window should, of course, somehow be part of my react application.

I would really appreciate it if someone could provide a minimal example here, on how these to things work together.

like image 446
George Welder Avatar asked Mar 11 '17 12:03

George Welder


1 Answers

To open a react component in a new window on button click and detect when the window is closed because the component will not simply call componentWillUnmount when you close the window Your app should look like this

App.js

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      // To keep track of the new window if opened or closed
      isNewWindow: false,
    };
  }

  render() {
    return(
    // onClose will be fired when the new window is closed
    // everything inside NewWindowComponent is considered props.children and will be
    // displayed in a new window
    {(this.state.isNewWindow) &&
    <NewWindowComponent
      onClose={() => this.setState({ isNewWindow: false })>
      <h2>This will display in a new window</h2>
    </NewWindowComponent> }

    <button
      onClick={() => this.setState({ isNewWindow: true })}>
      Open in new window</button>
    )
  }
}

NewWindowComponent.js

export default class NewWindowComponent extends Component {
  // Create a container <div> for the window
  private containerEl = document.createElement('div');

  // This will keep a reference of the window
  private externalWindow = null;

  // When the component mounts, Open a new window
  componentDidMount() {
    // The second argument in window.open is optional and can be set to whichever
    // value you want. You will notice the use of this value when we modify the main
    // electron.js file
    this.externalWindow = window.open('', 'NewWindowComponent ');

    // Append the container div and register the event that will get fired when the
    // window is closed
    if (this.externalWindow)
    {
      this.externalWindow.document.body.appendChild(this.containerEl);
      this.externalWindow.onunload = () => this.props.onClose();
    }
  }

  render() {
    return ReactDOM.createPortal(this.props.children, this.containerEl);
  }
}

electron-main.js or however your main electron file is named

...
function createWindow() {
  mainWindow = new BrowserWindow({
    ...
    // You need to activate `nativeWindowOpen`
    webPreferences: { nativeWindowOpen: true },
  });
  ...
  mainWindow.webContents.on('new-window',
    (event, url, frameName, disposition, options, additionalFeatures) =>
    {
      // This is the name we chose for our window. You can have multiple names for
      // multiple windows and each have their options
      if (frameName === 'NewWindowComponent ') {
        event.preventDefault();
        Object.assign(options, {
          // This will prevent interactions with the mainWindow
          parent: mainWindow,
          width: 300,
          height: 300,
          // You can also set `left` and `top` positions
        });
        event.newGuest = new BrowserWindow(options);
    }
  });
  ...
}
...
like image 99
akram-adel Avatar answered Nov 14 '22 23:11

akram-adel