I created a WindowPortal to open many new external windows/tabs.
https://codesandbox.io/s/modest-goldwasser-q6lig?file=/src/App.js
How can I pass props to a props.children in createPortal function?
I want pass newWindow as a prop for handling resize of new window.
import React, { useState, useRef, useEffect, useCallback, Children, cloneElement } from "react";
import { createPortal } from "react-dom";
import { create } from "jss";
import { jssPreset, StylesProvider, CssBaseline } from "@material-ui/core";
type WindowPortalProps = {
width: number;
height: number;
close: () => void;
id: number;
title: string;
};
const WindowPortal: React.FC<WindowPortalProps> = (props) => {
const [container, setContainer] = useState<HTMLElement | null>(null);
const newWindow = useRef<Window | null>(null);
const { title } = props;
const [jss, setJss] = useState<any>(null);
useEffect(() => {
// Create container element on client-side
setContainer(document.createElement("div"));
}, []);
const close = useCallback(() => {
props.close();
}, [props]);
useEffect(() => {
// When container is ready
if (container) {
setJss(create({ ...jssPreset(), insertionPoint: container }));
// Create window
newWindow.current = window.open(
"",
"",
`width=${props.width},height=${props.height},left=200,top=200,scrollbars,resizable,menubar,toolbar,location`,
) as Window;
// Append container
newWindow.current.document.body.appendChild(container);
newWindow.current.document.title = title;
const stylesheets = Array.from(document.styleSheets);
stylesheets.forEach((stylesheet) => {
const css = stylesheet as CSSStyleSheet;
const owner = stylesheet.ownerNode as HTMLElement;
if (owner.dataset.jss !== undefined) {
// Ignore JSS stylesheets
return;
}
if (stylesheet.href) {
const newStyleElement = document.createElement("link");
newStyleElement.rel = "stylesheet";
newStyleElement.href = stylesheet.href;
newWindow.current?.document.head.appendChild(newStyleElement);
} else if (css && css.cssRules && css.cssRules.length > 0) {
const newStyleElement = document.createElement("style");
Array.from(css.cssRules).forEach((rule) => {
newStyleElement.appendChild(document.createTextNode(rule.cssText));
});
newWindow.current?.document.head.appendChild(newStyleElement);
}
});
// Save reference to window for cleanup
const curWindow = newWindow.current;
curWindow.addEventListener("beforeunload", close);
// Return cleanup function
return () => {
curWindow.close();
curWindow.removeEventListener("beforeunload", close);
};
}
}, [container]);
return (
container &&
newWindow.current &&
jss &&
createPortal(
<StylesProvider jss={jss} sheetsManager={new Map()}>
<CssBaseline />
{props.children} -> how pass newWindow.current as externalWindow props?
</StylesProvider>,
container,
)
);
};
const ExpandedComponentForWindowPortal = ({ externalWindow, ...rest }) => {
const [countOfResize, setCountOfResize] = useState(0);
const doSomething = () => setCountOfResize(countOfResize + 1);
useEffect(() => {
externalWindow.addEventListener("resize", doSomething);
return () => {
externalWindow.removeEventListener("resize", doSomething);
setCountOfResize(0)
}
}, []);
return <></>;
}
const ComponentInExternalWindow = () => {
const closeWindow = () => {}
return (
<WindowPortal
title={"title"}
width={window.innerWidth}
heigth={window.innerHeigth}
key={2}
id={1}
close={closeWindow}
>
<ExpandedComponentForWindowPortal />
</WindowPortal>
)
}