skip to Main Content

I’m trying to make two React Apps communicate by sending messages containing stringified objects.

The parent (http://localhost:3000) sends a message through postMessage like so:

    let iframe = document.querySelector("iframe")

    useEffect(() => {
        if (!!localStorageObject && !!iframe) {
            iframe?.contentWindow?.postMessage(localStorageObject, "http://localhost:3001")
        }
    }, [localStorageObject, iframe])

    // ...file and start of return

   <iframe
       style={{minHeight: window.outerHeight, width: '100%', border: "none"}}
       referrerPolicy="strict-origin-when-cross-origin"
       src={myUrlWithParams}
       title="App"
       allow="clipboard-write"
       id={"iframe"}
   />

The iFrame (http://localhost:3001) does not recieve the message, at least not immediatly (I have to wait for a react soft refresh for the logs to show up).

The error thrown at first is:

Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('http://localhost:3001') does not match the recipient window's origin ('http://localhost:3000').

2

Answers


  1. I only got the error when the postMessage second parameter was different than the iframe source, you can change that for a * to make sure not to get this error, also you should use a ref for the iframe.

    See if this helps you:

    import { useRef } from "react";
    
    export default function App() {
    
        const iframeRef = useRef();
    
        const inputRef = useRef();
    
        const sendMessage = () => {
            iframeRef.current.contentWindow.postMessage(inputRef.current.value, "*");
        }
    
        return <>
            <input ref={inputRef} placeholder="Message" />
    
            <button onClick={sendMessage}>Send Message</button>
    
            <iframe
                ref={iframeRef}
                title="iframe"
                src="http://localhost:3000?somestuff=10&other=name">
            </iframe>
        </>;
    }
    
    Login or Signup to reply.
  2. This is because your iframe document hasn’t loaded yet when you call this postMessage() method, and hence the contentWindow you receive is the one of the original about:blank document, not your expected one.

    One could argue that the error message is a bit confusing here, and your dev tools could probably have been nicer by (also?) reporting that the location’s origin was about:blank (even if it’s the global document’s origin that’s been checked for postMessage()).

    But anyway, to workaround that issue, wait for the load event of your <iframe>. (I’m sorry I’m not a reactJS ninja, so I’ll let you the work of finding the best way to do so).

    Here is a vanilla repro setup with the solution applied: https://jsfiddle.net/382pz5er/ (outsourced because StackSnippet’s null origined frames make for a bad example here).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search