关于react.js:reactwebcomponentify组件介绍原码分析注意事项

42次阅读

共计 2549 个字符,预计需要花费 7 分钟才能阅读完成。

react-webcomponentify 是一个能够无需任何额定工作量就能将 react 组件打包 导出为 webComponent 的库。整个库在 gizp 之后仅有 1.5kb。


应用办法

根底

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>

进阶
向 react 传递数据:能够通过 html 的 attributes 传递字符串属性,通过 setProps 办法传递函数或者对象之类的属性

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>

每一个通过 react-webcomponentify 创立的自定义组件都有一个 setProps 实例办法

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

同样反对子组件

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>

原理剖析

1. 创立工程函数,应用 customElements 定义 webcomponent,通过 ShadowDom 隔离组件
2. 在类的构造函数中获取 html 标签的所有属性。定义一个 MutationObserver 监听属性的变动。调用 renderReact2Node 办法
3.renderReact2Node 办法作用是将 react 组件挂载到页面上。接管的参数有要导出的 react 组件、初始化数据(就是第 2 步获取到的属性)、指标父容器元素(就是第 1 步创立的 shandowDom)、onRender 回调。
4. 在 renderReact2Node 中定义一个高阶组件 PropBridge,作用是保护 state 状态,而后将该组件 ref 导出。挂载。
这样在 shadowDom 中通过调用 ref.current.setProps 就实现了通信。

  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. 在容器的 MutationObserver 的回调中调用 setProps。这样就实现了批改标签属性实时通信给 react
6. 在容器创立一个实例办法 setProps,对参数进行解决后调用 PropBridge 的 setProps,这样就实现了简单数据类型的传递。


注意事项
我在应用过程中遇到一个大坑。react 组件 webpack 导出的时候进行了分包。援用组件的 angular 我的项目也应用的 webpack。也进行了分包,所以 react 组件引入的时候,呈现了 bundle 错乱的问题。
起因是两份 webpack 配置外面 output.jsonpFunction 没有写,默认是 window 下的一个全局变量 webpackJsonp。
解决办法
1.react 导出不分包
2. 批改 react webpack 的 jsonpFunction。(在 webpack5 中叫 chunkLoadingGlobal)

正文完
 0