头图

react-webcomponentify is a library that can package and export react components as webComponents without any additional work. The entire library is only 1.5kb after gizp.


Instructions

basic

import React from "react";
import { registerAsWebComponent } from "react-webcomponentify";

export const ExampleReactComponent = () => {
  return <div> Hello </div>;
};

registerAsWebComponent(ExampleReactComponent, "example-component");

html

<!DOCTYPE html>
<html>
  ....
  <body>
    <example-component />
  </body>
  ....
</html>

Advanced
Pass data to react: You can pass string attributes through HTML attributes, and pass attributes such as functions or objects through the setProps method

import React from "react";
import { registerAsWebComponent } from "react-webcomponentify";

export const ButtonComponent = props => {
  return (
    <div>
      Hello <button onClick={props.onClick}>{props.text}</button>
    </div>
  );
};

registerAsWebComponent(ButtonComponent, "button-web");

html

<!DOCTYPE html>
<html>
  ....
  <body>
    <button-web text="click me" id="mybutton" />
  </body>
  ....
  <script>
    const myBtn = document.getElementById("mybutton");
    myBtn.setProps({
      onClick: () => console.log("btn was clicked")
    });
  </script>
</html>

Every custom component created by react-webcomponentify has an instance method setProps

element.setProps({
  ....
  /* 在这里设置你想要发送给react的属性 */
  ....
})

also supports subcomponent

import React from "react";
import { registerAsWebComponent } from "react-webcomponentify";

// You access the children just like you would in react (using this.props.children)
export const ComponentWithChild = props => {
  return (
    <div>
      Hello World
      {this.props.text}
      <div>{this.props.children}</div>
    </div>
  );
};

registerAsWebComponent(ComponentWithChild, "component-with-child");

html

<!DOCTYPE html>
<html>
  ....
  <body>
    <component-with-child text="I love children">
      <p>Some child</p>
    </component-with-child>
  </body>
  ....
</html>

Principle analysis

1. Create engineering functions, use customElements to define webcomponents, and isolate components through ShadowDom
2. Get all the attributes of the html tag in the constructor of the class. Define a MutationObserver to monitor property changes. Call the renderReact2Node method
3. The role of the renderReact2Node method is to mount the react component on the page. The received parameters include the react component to be exported, the initialization data (the attribute obtained in step 2), the target parent container element (the shandowDom created in step 1), and the onRender callback.
4. Define a high-level component PropBridge in renderReact2Node, whose role is to maintain the state state, and then export the component ref. Mount.
In this way, communication is realized by calling ref.current.setProps in shadowDom.

  class PropBridge extends React.PureComponent {
    state = { ...initialProps };
    setProps = (props: React.RefObject<PropBridge>) =>
      this.setState(() => props);
    render() {
      return <RComponent {...this.props} {...this.state} />;
    }
  }
  const propBridgeRef = createRef<PropBridge>();
    ReactDOM.render(<PropBridge ref={propBridgeRef} />, targetDomNode, () =>
    onRender(propBridgeRef)
  );

5. Call setProps in the callback of the container's MutationObserver. In this way, real-time communication of modified tag attributes to react is realized
6. Create an instance method setProps in the container, call the setProps of PropBridge after processing the parameters, so that the transfer of complex data types is realized.


Note
I encountered a big hole in the process of using it. When the react component webpack is exported, it is subcontracted. Angular projects that reference components also use webpack. Subcontracting was also carried out, so when the react component was introduced, there was a problem of bundle confusion.
The reason is that the output.jsonpFunction in the two webpack configurations is not written, and the default is a global variable webpackJsonp under the window.
Solution
1.react export without subcontracting
2. Modify the jsonpFunction of react webpack. (Called chunkLoadingGlobal in webpack5)


阿古达木
574 声望17 粉丝

牛逼的工程师就是能用简单的代码和思路写出复杂的功能