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)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。