gpt4 book ai didi

reactjs - 从 StencilJS 组件内部渲染 React 组件并将插槽映射到 props.children

转载 作者:行者123 更新时间:2023-12-05 05:02:40 34 4
gpt4 key购买 nike

我想将现有的 React 组件包装在 StencilJS 组件中。

我通过在 StencilJS componentDidRender 钩子(Hook)中调用 ReactDom.render 并在渲染后将其移动到 react 子元素中,我有一个 mvp 的东西,但是我想知道是否有更好的方法来实现这一目标。

我不喜欢这需要宿主内部的两个包装器元素,并且手动将插槽移动到 React 组件中感觉很恶心。

示例代码 - 我试图在此处呈现的现有 React 组件是来自 react-bootstrap 项目的 Bootstrap Alert,仅作为示例。

import {
Component,
ComponentInterface,
Host,
h,
Element,
Prop,
Event,
} from '@stencil/core';
import { Alert, AlertProps } from 'react-bootstrap';
import ReactDOM from 'react-dom';
import React from 'react';

@Component({
tag: 'my-alert',
styleUrl: 'my-alert.css',
shadow: false,
})
export class MyAlert implements ComponentInterface, AlertProps {
@Element() el: HTMLElement;

@Prop() bsPrefix?: string;
@Prop() variant?:
| 'primary'
| 'secondary'
| 'success'
| 'danger'
| 'warning'
| 'info'
| 'dark'
| 'light';
@Prop() dismissible?: boolean;
@Prop() show?: boolean;
@Event() onClose?: () => void;
@Prop() closeLabel?: string;
@Prop() transition?: React.ElementType;

componentDidRender() {
const wrapperEl = this.el.getElementsByClassName('alert-wrapper')[0];
const slotEl = this.el.getElementsByClassName('slot-wrapper')[0];

const alertProps: AlertProps = {
variant: this.variant,
dismissible: this.dismissible,
show: this.show,
onClose: this.onClose,
closeLabel: this.closeLabel,
transition: this.transition,
};

ReactDOM.render(
React.createElement(
Alert,
alertProps,
React.createElement('div', { className: 'tmp-react-child-el-class-probs-should-be-a-guid-or-something' })
),
wrapperEl
);

const reactChildEl = this.el.getElementsByClassName(
'tmp-react-child-el-class-probs-should-be-a-guid-or-something'
)[0];
reactChildEl.appendChild(slotEl);
}

render() {
return (
<Host>
<div class="alert-wrapper"></div>
<div class="slot-wrapper">
<slot />
</div>
</Host>
);
}
}

最佳答案

一些提示:

  • 您不需要 wrapperEl,您可以将您的 React 组件渲染到宿主元素 this.el 中。
  • 由于您没有使用 shadow,您可以克隆组件的插槽内容并将其用作 React 组件的子组件。
  • 除了 this.el.getElementsByClassName('slot-wrapper')[0] 你还可以使用 this.el.querySelector('.slot-wrapper'),或使用 element reference .
  • onClose 不应用作 prop 名称,因为 on... 也是事件处理程序的绑定(bind)方式,例如。 G。如果您的组件发出一个 'click' 事件,那么您可以通过在该组件上设置一个 onClick 处理程序来为它绑定(bind)一个处理程序。尽管您已将它装饰成一个事件,但这在我看来是行不通的。

codesandbox.io 上的工作示例:
https://codesandbox.io/s/stencil-react-mv5p4?file=/src/components/my-alert/my-alert.tsx
(这也适用于重新渲染)

import {
Component,
ComponentInterface,
Host,
h,
Element,
Prop,
Event,
} from '@stencil/core';
import { Alert, AlertProps } from 'react-bootstrap';
import ReactDOM from 'react-dom';
import React from 'react';

@Component({
tag: 'my-alert',
shadow: false,
})
export class MyAlert implements ComponentInterface {
@Element() host: HTMLMyAlertElement;

@Prop() bsPrefix?: string;
@Prop() variant?:
| 'primary'
| 'secondary'
| 'success'
| 'danger'
| 'warning'
| 'info'
| 'dark'
| 'light';
@Prop() dismissible?: boolean;
@Prop() show?: boolean;
@Prop() closeHandler?: () => void;
@Prop() closeLabel?: string;
@Prop() transition?: React.ElementType;

originalContent: any[];

componentDidLoad() {
// clone the original (slotted) content
this.originalContent = Array.from(this.host.childNodes).map(node =>
node.cloneNode(true),
);

this.componentDidUpdate();
}

componentDidUpdate() {
const alertProps: AlertProps = {
variant: this.variant,
dismissible: this.dismissible,
show: this.show,
onClose: this.closeHandler,
closeLabel: this.closeLabel,
transition: this.transition,
ref: el => el?.append(...this.originalContent), // content injected here
};

ReactDOM.render(React.createElement(Alert, alertProps), this.host);
}

render() {
return (
<Host>
<slot />
</Host>
);
}
}

关于reactjs - 从 StencilJS 组件内部渲染 React 组件并将插槽映射到 props.children,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62035376/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com