Ali Bhagat
Ali Bhagat

Reputation: 515

Rendering an iFrame within a React Portal

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

Answers (1)

Magnum
Magnum

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

Related Questions