在本教程中,你将学习如何在React中使用Web Components(别名自定义元素)。如果你想在之前就开始建立你自己的Web Components,请查看本教程。Web Components教程。否则,我们将在本教程中安装一个外部Web组件,以便在React中使用它。
你将学习如何将道具作为属性/属性传递给你的自定义元素,以及如何在React组件中为你的自定义元素的事件添加事件监听器。在第一步,你将手动传递props,然而,之后我将向你展示如何使用自定义React Hook来自动完成这一过程。自定义React Hook是一个库,可以毫不费力地将Web组件连接到React。
从React组件到Web组件。属性、属性和事件
假设我们想使用一个预制的Web组件,它在React组件中代表一个下拉组件。我们可以导入这个Web组件并在我们的React组件中渲染它:
import React from 'react';
import 'road-dropdown';
const Dropdown = props => { return <road-dropdown />;};
你可以通过npm install road-dropdown 来安装该Web组件。到目前为止,React组件只渲染了自定义元素,但没有向它传递任何道具。这并不像下面的方式那样简单地将道具作为属性传递,因为你需要以不同的方式将对象、数组和函数传递给自定义元素。
import React from 'react';
import 'road-dropdown';
const Dropdown = props => {
// doesn't work for objects/arrays/functions
return <road-dropdown {...props} />;
};
让我们看看我们的React组件将如何在我们的React应用程序中使用,以了解我们需要传递给我们的Web组件的props。
const props = {
label: 'Label',
option: 'option1',
options: {
option1: { label: 'Option 1' },
option2: { label: 'Option 2' },
},
onChange: value => console.log(value),
};
return <Dropdown {...props} />;
将label 和option 属性作为属性传递给我们的Web组件是没有问题的:
import React from 'react';
import 'road-dropdown';
const Dropdown = ({ label, option, options, onChange }) => {
return (
<road-dropdown
label={label}
option={option}
/>
);
};
然而,我们需要对options 对象和onChange 函数做些什么,因为它们需要被调整,不能简单地作为属性传递。让我们从对象开始。与数组类似,该对象需要作为JSON格式的字符串传递给Web组件,而不是一个JavaScript对象。
import React from 'react';
import 'road-dropdown';
const Dropdown = ({ label, option, options, onChange }) => {
return (
<road-dropdown
label={label}
option={option}
options={JSON.stringify(options)}
/>
);
};
对象就这样了。接下来,我们需要关注一下函数。我们需要为它注册一个事件监听器,而不是把它作为属性来传递。这就是我们可以在组件第一次被渲染时使用React的useLayoutEffect。
import React from 'react';
import 'road-dropdown';
const Dropdown = ({ label, option, options, onChange }) => {
const ref = React.useRef();
React.useLayoutEffect(() => {
const { current } = ref;
current.addEventListener('onChange', customEvent =>
onChange(customEvent.detail)
);
}, [ref]);
return (
<road-dropdown
ref={ref}
label={label}
option={option}
options={JSON.stringify(options)}
/>
);
};
我们正在为我们的自定义元素创建一个引用--它被作为ref属性传递给自定义元素--以便在我们的React钩子中添加一个事件监听器。由于我们从自定义下拉元素中派发了一个自定义事件,我们可以在这个onChange 事件上注册,并通过我们自己的onChange 处理程序将信息传播上去。自定义事件有一个细节属性,可以发送一个可选的有效载荷。
注意:如果你的Web组件中有一个内置的DOM事件(例如:click 或change 事件),你也可以注册到这个事件。然而,这个Web组件已经派发了一个符合React组件命名惯例的自定义事件。
一个改进是提取事件监听器的回调函数,以便在组件卸载时删除监听器。
import React from 'react';
import 'road-dropdown';
const Dropdown = ({ label, option, options, onChange }) => {
const ref = React.useRef();
React.useLayoutEffect(() => {
const handleChange = customEvent => onChange(customEvent.detail);
const { current } = ref;
current.addEventListener('onChange', handleChange);
return () => current.removeEventListener('onChange', handleChange);
}, [ref]);
return (
<road-dropdown
ref={ref}
label={label}
option={option}
options={JSON.stringify(options)}
/>
);
};
这就是为我们的回调函数添加一个事件监听器,该函数作为道具传递给我们的下拉组件。因此,我们使用了一个连接到自定义元素的引用来注册这个事件监听器。所有其他属性都作为属性传递给自定义元素。option 和label 属性被传递,没有修改。此外,我们将options 对象作为字符串化的JSON格式传递。最后,你应该可以在React中使用这个Web组件了。
React到Web组件库
上一节已经向你展示了如何将Web组件自己连接到React组件中。然而,这个过程可以通过一个包装器来自动完成,该包装器负责将对象和数组格式化为JSON并将函数注册为事件监听器。让我们来看看如何使用useCustomElement React Hook,它可以通过npm install use-custom-element 安装。
import React from 'react';
import 'road-dropdown';
import useCustomElement from 'use-custom-element';
const Dropdown = props => {
const [customElementProps, ref] = useCustomElement(props);
return <road-dropdown {...customElementProps} ref={ref} />;
};
自定义钩子通过将所有数组和对象格式化为JSON,保持字符串、整数和布尔值不变,并将函数从自定义道具中移除,以自定义格式为我们提供所有属性。相反,这些函数将被注册为钩子中的事件监听器。不要忘记把ref属性也传给你的Web组件,因为正如你之前所看到的,它需要注册所有回调函数到Web组件。
如果你想了解更多关于这个在React中集成Web组件的自定义钩子,请查看它的文档。在那里你还可以看到如何为道具创建自定义映射,因为你可能想把道具中的onClick 回调函数映射到Web组件中的内置click 事件。另外,如果你对这个钩子有任何反馈,请让我知道。最后,如果你在你的项目中使用这个Web组件钩子,请通过给它一颗星来支持它。
你已经看到,在React Components中使用Web Components并不困难。你只需要注意JSON格式化和事件监听器的注册。之后,一切都应该开箱即用。如果你不想自己做这个繁琐的过程,你可以使用自定义钩子来做。请在评论中告诉我你的想法 :-)