I am trying to render a dynamically generated react component in a react app using createProtal. When I call createProtal from a class the component is not rendered.
Handler.ts
the class the contains the business logic
export class Handler {
private element: HTMLElement | null;
constructor(selector: string) {
this.element = document.getElementById(selector);
}
attachedEvent() {
this.element?.addEventListener("mouseenter", () => {
let cancel = setTimeout(() => {
if (this.element != null)
this.attachUi(this.element)
}, 1000)
this.element?.addEventListener('mouseleave', () => {
clearTimeout(cancel)
})
})
}
attachUi(domNode: HTMLElement) {
createPortal(createElement(
'h1',
{className: 'greeting'},
'Hello'
), domNode);
}
}
Main.tsx
the react component that uses Handler.ts
const handler = new Handler("test_comp");
export default function Main() {
useEffect(() => {
// @ts-ignore
handler.useAddEventListeners();
});
return (
<>
<div id="test_comp">
<p>Detect Mouse</p>
</div>
</>
)
}
However when I repleace attachUi
function with the function below it works
attachUi(domNode: HTMLElement) {
const root = createRoot(domNode);
root.render(createElement(
'h1',
{className: 'greeting'},
'Hello'
));
}
What am I missing?
React uses something called Virtual DOM. Only components that are included in that VDOM are displayed to the screen. A component returns something that React understands and includes to the VDOM.
createPortal(...)
returns exactly the same as <SomeComponent ... />
So if you just do: const something = <SomeComponent />
and you don't use that variable anywhere, you can not display it. The same is with createPortal
. const something = createPortal(...)
. Just use that variable somewhere if you want to display it. Add it to VDOM, let some of your components return it.
Your structure is
App
-children
-grand children
-children2
And your portal is somewhere else, that is not attached to that VDOM. You have to include it there, if you want to be displayed.
In your next example using root.render you create new VDOM. It is separated from your main one. This is why it is displayed