User Tools
Table of Contents
Render React App on GWT
React Side
Normal React App will look like this in index.js
// index.js ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') );
You need to make following changes.
- Surround it in function clause
- Export the function as module
- Assign module function to window property
// index.js export function renderComponent(selector) { ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById(selector) ); } module.exports = { renderComponent: renderComponent, }; window.renderComponent= renderComponent;
Simply build js file (bundle.js etc…) and put it to your GWT project.
For SnmpManager, put it in snmpmanager/web-app/js
Load JavaScript file in gsp header before GWT.
GWT Side
In constructor of GWT Component (such as Panel), add some child component with distinctive ID.
// ReactPanel.java public class ReactPanel extends VerticalPanel { public ReactPanel() { Label label = new Label(); label.getElement().setId("react-hostTree-root"); add(label); } }
In the same class, override onLoad() method and create native method which calls renderComponent() function of React App you just made above.
// ReactPanel.java @Override protected void onLoad() { super.onLoad(); renderHostTreeReact("react-hostTree-root"); } public native void renderHostTreeReact(String containerId) /*-{ $wnd.renderComponent(containerId); }-*/;
You need to put render method in onLoad() method otherwise React complains there is no such element with ID “react-hostTree-root”. GWT doesn't necessary show all component in the browser when constructor is called.
This is all the work you need to put React App in GWT.
If your React app with Redux, nothing shouldn't be different. Everything should work in the same way as you run ReactRedux App with nodeJS.
Interaction between GWT and ReactRedux
We are going to need to create GwtHolder.js. This class allows React Application to call function (native method) in GWT.
Dispatching Redux Action from GWT
In index.js of ReactRedux App, add following codes.
// index.js import * as bitcoinActions from './actions/bitcoinActions'; export function fetchBitcoinPrice(code) { store.dispatch(bitcoinActions.fetchBitcoinPrice(code)) } module.exports = { fetchBitcoinPrice: fetchBitcoinPrice, renderComponent: renderComponent, }; window.fetchBitcoinPrice= fetchBitcoinPrice; window.renderComponent= renderComponent;
Above code basically exporting function that dispatch redux action.
By that, we can call fetchBitcoinPrice(code) function from GWT native method as follows.
// ReactPanel.java public native void reactAction() /*-{ $wnd.fetchBitcoinPrice("EUR"); }-*/;
From GWT code, we can call reactAction() method just like other JAVA method in GWT.
Invoke GWT method from React App
React Side
We create JavaScript class (GwtHolder.js) in React App to interface React and GWT.
// GwtHolder.js let gwtComp let rateCodeFunc; class GwtHolder { constructor() { } static setGwtComp(comp) { gwtComp = comp; } static setRateCodeFunc(func) { rateCodeFunc = func; } static rateCodeFunc(rate, code) { if (rateCodeFunc === undefined) { console.error("rateCodeFunc is undefined"); } else { console.log("calling rateCodeFunc"); console.log(rate + " and " + code); rateCodeFunc(gwtComp, rate, code); } } } export default GwtHolder
Feature of GwtHolder class is
- Static variable gwtComp to store JavaScript object which represents GWT component
- Static variable rateCodeFunc to store function which is native method in GWT
React App can all GWT native method through GwtHolder as shown below.
import GwtHolder from '../GwtHolder'; GwtHolder.rateCodeFunc(rate, code);
Export GwtHolder in index.js so that GWT can see it. Later GWT will inject component and functions into GwtHolder.js
// index.js module.exports = { fetchBitcoinPrice: fetchBitcoinPrice, renderComponent: renderComponent, GwtHolder: GwtHolder, }; window.fetchBitcoinPrice= fetchBitcoinPrice; window.renderComponent= renderComponent; window.GwtHolder= GwtHolder;
GWT Side
In GWT, write native method (JavaScript function) to be passed to GwtHolder and JAVA method which actually do some work with GWT.
// ReactPanel.java public native void price(ReactPanel reactPanel, String price, String code) /*-{ var message = "Price given to GWT from React is " + price + " and code is " + code; console.log(message); console.log(reactPanel); reactPanel.@com.errigal.ems.client.dashboard.panel.ReactPanel::gwtAnnounce(Ljava/lang/String;)(message); }-*/; public void gwtAnnounce(String message) { WindowDialog.notify(message); }
So above code, native method price() will be passed to GwtHolder.js and bridge JavaScript and GWT.
We need to accept GWT Component instance as one of parameters. GWT Component means the class where all Java Code we write is written. In this case ReactPanel.
The reason is once price() native method is passed to React side, “this” keyword cannot be used because “this” means React App, not GWT component.
gwtAnnounce() method is normal Java method. In this case, it will show popup with message in GWT app.
So sequence of calling GWT method from React App will be
- React App calls GwtHolder.rateCodeFunc()
- GwtHolder.rateCodeFunc() adds gwtComp as parameter when it calls rateCodeFunc() which is ReactPanel.price() given from GWT.
- ReactPanel.price() do its job and calls ReactPanel.gwtAnnounce().
Now we have function (native method) to pass to React. So all we need to do is actually pass it on to React. We can do so by adding extra code in renderReact method.
// ReactPanel.java public native void renderHostTreeReact(String containerId) /*-{ var reactPanel = this; var func = reactPanel.@com.errigal.ems.client.dashboard.layouts.ReactPanel::price(Lcom/errigal/ems/client/dashboard/layouts/ReactPanel;Ljava/lang/String;Ljava/lang/String;); $wnd.renderComponent(containerId); $wnd.GwtHolder.setGwtComp(reactPanel); $wnd.GwtHolder.setRateCodeFunc(func); }-*/;
Why not "this" in native method for React
If you write GWT native method to be given to React App without argument “ReactPanel reactPanel” like below,
// malfunction - ReactPanel.java public native void price(String price, String code) /*-{ var message = "Price given to GWT from React is " + price + " and code is " + code; console.log(message); console.log(this); this.@com.errigal.ems.client.dashboard.panel.ReactPanel::gwtAnnounce(Ljava/lang/String;)(message); }-*/; public void gwtAnnounce(String message) { WindowDialog.notify(message); }
First, IntelliJ won't give you any error because syntax are perfect. IntelliJ recognise this.~~~.gwtAnnounce() method exists and executable from native method.
But when it actually executed from React, browser console tells you “gwtAnnounce is not function” or “no such property gwtAnnounce”.
If you have look at console log before the error, you'll see javascript object “Window” is outputted. That is React App object.
This is why you have to take GWT component itself (For this page's example, “ReactPanel reactPanel”) as one of arguments.
Using bind method like below but no avail.
// malfunction - ReactPanel.java public native void renderHostTreeReact(String containerId) /*-{ var reactPanel = this; var func = reactPanel.@com.errigal.ems.client.dashboard.layouts.ReactPanel::price(Ljava/lang/String;Ljava/lang/String;); func.bind(this); $wnd.renderComponent(containerId); $wnd.GwtHolder.setRateCodeFunc(func); }-*/;
Why not simply gwtComp.function()
import GwtHolder from '../GwtHolder'; GwtHolder.getGwtComp().price(rate, code);
This will give you “Uncaught TypeError: a.price is not a function” in browser console log.
I suspect we need to take some extra step to call GWT native method directly from javascript.

