Mount vue component in react with webcomponents
Tags: vue, react, webcomponents
Published: 2018-11-21 23:08:16

---
title: Mount vue component in react with webcomponents
published: true
description: 
tags: vue,react,webcomponents
---

I tried helpers to mount react and vue components via webcomponents.

https://github.com/mizchi/wc-helpers

My goal is to try micro-frontend.

```typescript
import {
  vueElementFactory,
  reactElementFactory,
  encodeProps
} from "@mizchi/wc-helpers";

// register
customElements.define("my-react-component", reactElementFactory(MyReactApp));
customElements.define("my-vue-component", vueElementFactory(MyVueApp));

// run
const state = { a: 0 };
const encoded = encodeProps(state);
document.body.innerHTML = `
  <my-react-component data-props="${encoded}"></my-react-component>
  <my-vue-component data-props="${encoded}"></my-vue-component>
`;
```

## Mount another platform

- my-react-component(depth=n) => my-vue-component(depth=n-1)
- my-vue-component(depth=n) => my-react-component(depth=n-1)

![](https://camo.githubusercontent.com/962476ebcc8ed34d034d1bf767babd7b3ff7752e/68747470733a2f2f6779617a6f2e636f6d2f30616461626236303064643530376462326163303239313965613233613032662e676966)

HTML

![](https://i.gyazo.com/08d8a34a99f7e1f417f1ae7314ef5807.png)

Code

```typescript
import Vue from "vue";
import Component from "vue-class-component";
import React from "react";
import { vueElementFactory, reactElementFactory, encodeProps } from "..";

// Vue
@Component({
  props: ["depth"]
})
class MyVueApp extends Vue {
  now: number = Date.now();
  render(h: any) {
    const depth = parseInt(this.$props.depth, 10);
    if (depth > 0) {
      return h(
        "div",
        {
          style: {
            paddingLeft: "10px",
            backgroundColor: "rgba(0, 255, 0, 0.3)"
          }
        },
        [
          h("p", {}, `vue: ${depth} createdAt:${this.now}`),
          h("my-react-component", {
            attrs: {
              "data-props": encodeProps({ depth: depth - 1 })
            }
          })
        ]
      );
    } else {
      return h(
        "p",
        {
          style: {
            paddingLeft: "10px",
            backgroundColor: "rgba(0, 255, 0, 0.3)"
          }
        },
        `vue: 0 - createtAt:${this.now}`
      );
    }
  }
}
customElements.define("my-vue-component", vueElementFactory(MyVueApp));

// React
class MyReactApp extends React.PureComponent<{ depth: string }> {
  now: number = Date.now();
  render() {
    const h = React.createElement;
    const depth = parseInt(this.props.depth, 10);
    if (depth > 0) {
      return h(
        "div",
        {
          style: {
            paddingLeft: "10px",
            backgroundColor: "rgba(255, 0, 0, 0.3)"
          }
        },
        h("p", {}, `react: ${depth} createdAt: ${this.now}`),
        h("my-vue-component", {
          "data-props": encodeProps({ depth: depth - 1 })
        })
      );
    } else {
      return h(
        "p",
        {
          style: {
            paddingLeft: "10px",
            backgroundColor: "rgba(255, 0, 0, 0.3)"
          }
        },
        "react 0: createdAt " + this.now
      );
    }
  }
}
customElements.define("my-react-component", reactElementFactory(MyReactApp));

// run
// const root = document.querySelector(".root");

let state = { depth: 4 };
const entry = document.createElement("my-react-component");
entry.setAttribute("data-props", state.depth.toString());
document.body.appendChild(entry);

setInterval(() => {
  state = { depth: state.depth + 1 };
  entry.setAttribute(
    "data-props",
    encodeProps({ depth: (state.depth % 6) + 3 })
  );
}, 1000);
```

## How it works

- Encode json to safe string
- Define Component
- Listen `data-props`'s `attributeChangedCallback`
- re-render

See implementation (114 lines) https://github.com/mizchi/wc-helpers/blob/master/index.ts

## Why `wc-helper` needs encode

WebComponents takes properties as string only. If you need to handle event handlers, try `lit-html` and `lit-html/lib/lit-extended`.

https://github.com/Polymer/lit-html