Reputation: 515
I was creating a Logger
service which would track events within my application. To make the Logger
service generic, I used React's Portal to capture the events fired in my application. The basic idea of my application is:
<LoggerPortal>
<App>
</LoggerPortal>
This worked well for my use case until the point that I used an iFrame
within my application.
Consider a very simple component that renders an iFrame:
const Frame = props => {
const refiFrame = useRef(null);
useEffect(() => {
console.log(refiFrame.current.contentDocument);
}, []);
return (
<>
<iframe id="i-framed-you" title="original-iframe-title" ref={refiFrame} />
</>
);
};
Now, when I render this Frame
component above without the Portal wrapped around it, the iframe.contentDocument
logs as expected.
ReactDOM.render(<Frame />,rootElement)
But when I render the Frame
component wrapped within a Portal the value of iFrame.contentDocument
is null.
ReactDOM.render(
<LoggerPortal>
<Frame />
</LoggerPortal>,
rootElement
);
Here is a codesandbox that has an app that depicts my problem. Has anyone seen this issue when using portals and iFrame? Am I missing something obvious here?
Upvotes: 4
Views: 5951
Reputation: 2395
Tricky problem!
useRef
doesn't cause a re-render when you make changes to have React add or remove DOM nodes. In your case, attaching an iframe
to your <Portal>
's props.children
, thus your console is returning null
. You'll have to use a callback ref instead: useCallback
So, to get the ref to your iframe, you can try:
let refiFrame = useCallback(node => {
refiFrame = node
});
Here is a working modified version of your codesandbox: https://codesandbox.io/s/portal-iframe-dmmnx
Upvotes: 2