4

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?

Ali Bhagat
  • 475
  • 1
  • 6
  • 15

1 Answers1

2

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

Magnum
  • 2,299
  • 4
  • 17
  • 23