I'm trying to get two React applications to communicate by sending messages containing stringified objects.
The parent (http://localhost:3000) sends a message via postMessage
like this:
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"} />
iFrame (http://localhost:3001) does not receive the message, at least not immediately (I have to wait for react soft refresh to show the log).
The first error thrown 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').
This is because when you call this
postMessage()
method, your iframe document has not yet loaded, so thecontentWindow
you receive is the originalabout:blank
one of the documents, not the one you expected.One might say that the error message here is a bit confusing, and your development tools might be better off (also?) reporting that the source of the location is
about:blank
(even if it is Check theorigin
of the global document forpostMessage()
).But anyway, to solve the problem, wait for the
load
event of<iframe>
. (Sorry, I'm not a reactJS ninja, so I'll let you find the best way to do this).This is a trivial repro setup with the solution applied: https://jsfiddle.net/382pz5er/ (outsourced because StackSnippet's null origin frame is a bad example here).