@coin-voyage/paykit
Version:
Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.
35 lines (34 loc) • 1.47 kB
JavaScript
import { useLayoutEffect, useState } from "react";
import { createPortal } from "react-dom";
import { paykitVersion } from "../../../utils/version";
const Portal = ({ selector = "__COIN_VOYAGE__", children }) => {
const [portalTarget, setPortalTarget] = useState(null);
// useLayoutEffect is used here to synchronously set up the portal target
// before the component renders. This is the standard pattern for portals.
useLayoutEffect(() => {
let divCreated = false;
const selectorPrefixed = `#${selector.replace(/^#/, "")}`;
let element = document.querySelector(selectorPrefixed);
if (!element) {
const div = document.createElement("div");
div.setAttribute("id", selector);
div.setAttribute("data-pay", paykitVersion);
document.body.appendChild(div);
element = div;
divCreated = true;
}
// Setting state here is intentional - we need to trigger a re-render
// after the DOM element is available for the portal to render into
// eslint-disable-next-line react-hooks/set-state-in-effect
setPortalTarget(element);
return () => {
if (divCreated && element?.parentNode) {
element.parentNode.removeChild(element);
}
};
}, [selector]);
if (!portalTarget)
return null;
return createPortal(children, portalTarget);
};
export default Portal;