React与Next.js中如何使用postMessage和addEventListener实现iframe通信
问题原因
- origin校验拦截了合法消息:浏览器
message事件的origin属性返回值不带末尾斜杠,你代码中校验的https://wyftk.sse.codesandbox.io/多了末尾斜杠,所有消息都会被直接拦截,这是最核心的失效原因。 - 父页面发消息时机可能早于iframe加载完成:未做iframe加载完成判断的情况下,点击按钮发消息时如果iframe内部的监听事件还未挂载,会出现消息丢失。
- 事件监听未清理:组件卸载时没有移除
message事件监听,会导致重复绑定、内存泄漏问题。 - 不存在你猜测的Next.js环境下React Hook使用addEventListener的兼容问题。
修复后代码
父页面 index.js
import { useRef, useEffect, useState } from "react"; const IndexPage = () => { const IFrameRef = useRef(null); const [receivedMsg, setReceivedMsg] = useState(""); // 标记iframe是否加载完成 const [iframeLoaded, setIframeLoaded] = useState(false); // 统一声明origin,避免写错 const ALLOW_ORIGIN = "https://wyftk.sse.codesandbox.io"; const sendMessage = () => { console.log("send parents msg"); if (!IFrameRef.current || !iframeLoaded) return; IFrameRef.current.contentWindow.postMessage( "Hello son", ALLOW_ORIGIN ); }; useEffect(() => { const handleMessage = (e) => { if (e.origin !== ALLOW_ORIGIN) return; setReceivedMsg("child message =" + e.data); }; window.addEventListener("message", handleMessage); // 组件卸载时清理监听 return () => window.removeEventListener("message", handleMessage); }, []); return ( <div> <h1>parents iframe</h1> <button type="primary" onClick={sendMessage} disabled={!iframeLoaded} > send sms to child </button> <iframe ref={IFrameRef} style={{ width: "100%", height: "600px" }} src="/model" id="calculation" title="model" onLoad={() => setIframeLoaded(true)} ></iframe> <p>{receivedMsg}</p> </div> ); }; export default IndexPage;
子页面 model.js
import { useEffect, useState } from "react"; const ModelPage = () => { const [receivedMsg, setReceivedMsg] = useState(""); const ALLOW_ORIGIN = "https://wyftk.sse.codesandbox.io"; const sendMessage = () => { console.log("send child msg"); window.parent.postMessage("Hi dad!", ALLOW_ORIGIN); }; useEffect(() => { const handleMessage = (e) => { if (e.origin !== ALLOW_ORIGIN) return; setReceivedMsg("parent message =" + e.data); }; window.addEventListener("message", handleMessage); return () => window.removeEventListener("message", handleMessage); }, []); return ( <div> <h2>model page</h2> <button type="primary" onClick={sendMessage}> send sms to parents </button> <p>{receivedMsg}</p> </div> ); }; export default ModelPage;
内容的提问来源于stack exchange,提问作者AlexMoshi
相关产品推荐
相关产品推荐

