1

I have a vaadin7 application to which I am trying to integrate a sample react application. It is working properly when I implement the React component creation inside a button click. But it is not working if I put the code outside the button click. It shows error "Uncaught TypeError: Cannot read property 'appendChild' of null at Module.11 (index.js:9) at u (bootstrap:84) at t (bootstrap:45) at Array.r [as push] (bootstrap:32) at main.90a85973.chunk.js:1" while inspecting.

In vaadin application, i am creating div named "root" and in the index.js of sample react application, I am trying to get the root div created from vaadin and appending "react-root" to "root" div so as to fit the react application in my vaadin layout.

Please find below code for vaadin ui

CustomLayout layout = null;
        try {
            String dynamicHtml = "<div id=\"root\"></div>";
            layout = new CustomLayout(new ByteArrayInputStream(dynamicHtml.getBytes()));
            System.out.println("JS Layout");
        } catch (IOException e) {
            System.out.println("could not create custom layaout"+ e);
        }
        uimainLayout.addComponent(layout);
        

//If the below 4 lines of code are added inside the button click, the reactcomponent is rendered inside the layout properly on clicking the button . Otherwise it is showing the "Uncaught TypeError: Cannot read property 'appendChild' of null"

        VerticalLayout jsmainLayout = new VerticalLayout();
        ReactComponent reactComponent=new ReactComponent();
        jsmainLayout.addComponent(reactComponent);
        uimainLayout.addComponent(jsmainLayout);

        getMainLayout().addComponent(uimainLayout);
        setCompositionRoot(getMainLayout());

My Reactcomponent

@JavaScript({"<ip:port>/static/js/2.1f3e22a9.chunk.js","<ip:port>/static/js/3.583f7bad.chunk.js","<ip:port>/static/js/runtime-main.23689a58.js","<ip:port>/static/js/main.90a85973.chunk.js","ReactComponentConnector.js"})
@StyleSheet("<ip:port>/static/css/main.a617e044.chunk.css")
public class ReactComponent extends AbstractJavaScriptComponent {
    public ReactComponent() {
         System.out.println("Inside ReactComponent");
        
    }
    @Override
    protected ReactComponentState getState() {
        return (ReactComponentState) super.getState();
    }
}

ReactComponentState

public class ReactComponentState extends JavaScriptComponentState {
    private static final long serialVersionUID = -3283446856435450054L;
}

ReactComponentConnector.js

window.com_p1_p2_ReactComponent = function () {

}

Index.js of my sample react application

const rootEl = document.createElement('div')
rootEl.setAttribute('id', 'react-root');
//error points to the below line
const parentEl =document.getElementById('root');
parentEl.appendChild(rootEl)

ReactDOM.render(
    <App />
  ,
  rootEl
);
reportWebVitals();
AJS91
  • 11
  • 2

1 Answers1

0

It's not clear exactly what it is that triggers running the code listed for index.js, but it would seem like it's run before the contents of the custom layout has been initialized. In that way, no element with the id root exists and this would cause the reported error.

I assume creation happens through new ReactComponent(this.getElement()) from inside the JS connector initializer. If this is the case, then they reason for the problem is that both the actions (set custom layout content and initialize the JS connector) are sent to the browser in the same batch, but the connector is initialized in an earlier phase. If the JS component is sent in a batch triggered though a click listener, then this won't be a problem.

To solve this, you could use a direct element reference instead of relying on getElementById in combination with an id defined in the content of a custom layout. The easiest way would be if you'd restructure to use the this.getElement() instance that you're now passing to the ReactComponent constructor.

Leif Åstrand
  • 7,820
  • 13
  • 19
  • Astrand: I have updated the question after removing the code from the function in the ReactComponentConnector.js. Same behavior and same error – AJS91 Jul 19 '21 at 19:18
  • Does that mean that the code from `index.js` is run immediately when that file is loaded? I would then assume it's loaded through the `@JavaScript` annotation values. In that case, it will always be loaded too early. You need to make it so that it's run only after Vaadin has added the target element to the DOM. I'd recommend removing the `CustomLayout` and instead using a `CssLayout` with `setId("root")` so that the element is present when state change events are fired, and then wrapping the `index.js` logic in a function that you run from a state change handler in the connector JS. – Leif Åstrand Jul 19 '21 at 20:35