2

This is probably a little bit tricky - I want to render React inside of a Web Component prepared via Stencil, but I get the 'Invariant Violation: Target container is not a DOM element.':

import { Component, Prop } from "@stencil/core";
import { format } from "../../utils/utils";
import ReactDOM from 'react-dom';
import React from "react";
import { LikeButton } from './../LikeButton';

const e = React.createElement;

@Component({
  tag: "my-component",
  styleUrl: "my-component.css",
  shadow: true
})
export class MyComponent {
  @Prop() first: string;
  @Prop() middle: string;
  @Prop() last: string;

  private getText(): string {
    return format(this.first, this.middle, this.last);
  }

  componentWillLoad() {
    console.log("here i am - the React render");
    const domContainer = document.querySelector("#like_button_container");
    ReactDOM.render(e(LikeButton), domContainer);
  }

  render() {
    return (
      <div>
        Hello, World! I'm {this.getText()}{" "}
        <div id="like_button_container">React container</div>
      </div>
    );
  }
}
Michał J. Gąsior
  • 1,457
  • 3
  • 21
  • 39
  • 1
    Possible duplicate of [Invariant Violation: \_registerComponent(...): Target container is not a DOM element](https://stackoverflow.com/questions/26566317/invariant-violation-registercomponent-target-container-is-not-a-dom-elem) – Danny '365CSI' Engelman Apr 19 '19 at 15:40

1 Answers1

3

You can use the @Element() decorator and using that to query for the domContainer element under shadowRoot. shadowRoot is need with @Element() in this case because you have shadow set to true:

import { Component, Element, Prop } from "@stencil/core";
import { format } from "../../utils/utils";
import ReactDOM from 'react-dom';
import React from "react";
import { LikeButton } from './../LikeButton';

const e = React.createElement;

@Component({
  tag: "my-component",
  styleUrl: "my-component.css",
  shadow: true
})
export class MyComponent {
  @Element() el: HTMLElement;
  @Prop() first: string;
  @Prop() middle: string;
  @Prop() last: string;

  private getText(): string {
    return format(this.first, this.middle, this.last);
  }

  componentWillLoad() {
    const domContainer = this.el.shadowRoot.querySelector("#like_button_container");
    ReactDOM.render(e(LikeButton), domContainer);
  }

  render() {
    return (
      <div>
        Hello, World! I'm {this.getText()}{" "}
        <div id="like_button_container">React container</div>
      </div>
    );
  }
}

I had intermittent issues when running this in stenciljs development mode. When refreshing the page I experienced issue perhaps due to cache, but if I triggered a reload by saving the stenciljs component file containing this code it usually worked. This may be more related to stencil-dev-server rather than the code.

Hopefully that helps!

Alexander Staroselsky
  • 37,209
  • 15
  • 79
  • 91