Open jacobjuul opened 1 year ago
We explored a few options for direct access, but the only option we found entailed crawling the DOM children and turning them into React nodes; while functional, it was very messy and create a lot of React key
errors, so it wasn't really a viable solution.
If you just want to render that text, and don't need access to the value, slots are what you want. Given how you've written the above component, you can render that text anywhere you want by rendering <slot></slot>
(as many times as you want). If you want "fallback" content to show if they use doesn't provide a value, you can put that inside the slot
tag. If you want multiple of these user-defined content blocks, you can use named slots, too.
<my-component>
<span slot="content1">some text I want access to in react</span>
<p slot="content2">some other content I want access to in react</p>
</my-component>
Then render these with <slot name="content1"></slot>
and <slot name="content2"></slot>
.
If you need direct access to the value, I would suggest putting it in an attribute on the WC, or setting it on a property after the component is mounted.
If you think this would benefit from further discussion, or if not, I'd invite you to join our community discord. There are quite a few threads there about R2WC, and t's become a really great spot to ask questions, share knowledge, and connect about other interests too.
Thanks so much. I actually ended up solving it with a slot although not exactly what I wanted.
If you can explain your needs a bit more, I might be able to incorporate something into a future version that solves the problem better.
I solved as follow: this code worked in react component.
const slotName = 'children' // set a slot name id whatever you like.
const {children} = props; // this children is comes from React children property original.
useEffect(function() {
// pick all children from custom element and set a slot property for them.
const children: HTMLElement[] = props.container?.host?.children;
if(children){
for(let i=0; i<children.length; i++){
children[i].setAttribute('slot', slotName)
}
}
},[])
return (
<div>
{children}
// set a slot for html element.
<slot name={slotName}></slot>
</div>
)
how about put this logic into React-to-web-component
?
i think it won't cause some issue like React key
error?
what cause this case is confused me. i did not meet this case while creating custom element by svelte. so what's the problem? is it a limited by web component or svelte has solved this issue in some way?
I have got the reason in this code. it's not a limit by custom element but React.
React render need a root element as the root. so you provide this
(custom-element) as its root. so after render, the origin children element by html will be replaced.
if (options.shadow) {
this.container = this.attachShadow({
mode: options.shadow,
}) as unknown as HTMLElement
} else {
this.container = this
}
this[contextSymbol] = renderer.mount(
this.container,
ReactComponent,
this[propsSymbol],
)
To avoid prevent this issue. how about select or create a root instead of this
?
like bellow:
let rootContainer = this;
const thisCustomElement = this;
// 1. check if `thisCustomElement ` has a some children
const hasChildren = this.CustomEelement.children.length > 0;
if(hasChildren){
const childRoot = document.createElement('div');
thisCustomElement.appendChild(childRoot);
rootContainer = childRoot;
}
I have got the reason in this code. it's not a limit by custom element but React.
React render need a root element as the root. so you provide
this
(custom-element) as its root. so after render, the origin children element by html will be replaced.if (options.shadow) { this.container = this.attachShadow({ mode: options.shadow, }) as unknown as HTMLElement } else { this.container = this } this[contextSymbol] = renderer.mount( this.container, ReactComponent, this[propsSymbol], )
To avoid prevent this issue. how about select or create a root instead of
this
? like bellow:let rootContainer = this; const thisCustomElement = this; // 1. check if `thisCustomElement ` has a some children const hasChildren = this.CustomEelement.children.length > 0; if(hasChildren){ const childRoot = document.createElement('div'); thisCustomElement.appendChild(childRoot); rootContainer = childRoot; }
@christopherjbaker check this please.
replace all origin children or create a new child root node maybe could be a property choice when using custom html. both of then are useful. one is need keep origin node as children. another don't need keep it can be used as a fallback on connected error or custom html not work.
I started conversation on this topic a while ago on Discord as well, here is the link for the thread for reference: https://discord.com/channels/1007137664606150746/1113836418716942358/1113836418716942358
I have also encountered this problem. This problem is too critical. If children cannot include nested components, and do this in attributes, the converted components will be quite troublesome to use.
That's a usecase we would need as well for web-components. An Accordeon-Component for example doesn't need to know it's children beforehand and it would be necessary to just be able to drop other components/content in.
Is there a workaround that works in the meantime?
Let's say I have this webcomponent
I assumed the text would be available as
children
in the react component, but it's not as far as I can tell. Can I accessthis.textContent
somehow instead?