React挂钩会更改postMessage

时间:2019-08-01 07:06:09

标签: javascript reactjs

我有一个使用useState处于某种状态的组件。

此组件将打开一个新选项卡,并且应该在postMessage上收到消息事件。 由于某种原因,在我收到事件后,状态会返回到其初始状态。

我尝试将状态保存到localStorage并起作用。

index.js

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";

const App = () => {
  const [state, setState] = useState("hello");

  const onClick = () => {
    setState("world");
    window.open("tab.html");
  };

  const onMessageReceivedFromIframe = event => {
    console.log("onMessageReceivedFromIframe", state, event);
  };

  const addIframeListener = () =>
    window.addEventListener("message", onMessageReceivedFromIframe);
  const removeIframeListener = () =>
    window.removeEventListener("message", onMessageReceivedFromIframe);

  useEffect(() => {
    addIframeListener();
    return () => {
      removeIframeListener();
    };
  }, []);

  useEffect(() => {
    console.log("Current state: ", state);
  }, [state]);

  return <button onClick={onClick}>Click here</button>;
};

ReactDOM.render(<App />, document.getElementById("app"));

tab.html

<html>
  <body>
    tab
    <script>
      setTimeout(() => {
      console.log("post");
      window.opener.postMessage("some message", "https://9jzj7.csb.app");
      window.close();
      }, 2000);
    </script>
  </body>
</html>

状态返回到其初始状态。

一个演示可以在这里看到: https://codesandbox.io/s/trusting-waterfall-9jzj7

顺便说一句: 我知道没有从tab.html触发该事件,但是仍有一个事件在打开标签页时触发。

2 个答案:

答案 0 :(得分:2)

似乎您的问题出在效果钩子的deps数组上,并且在每个渲染器上都创建了onMessageReceivedFromIframe。 以下解决方案应能按预期工作。这是指向codesandbox

的链接
const App = () => {
  const [state, setState] = useState("hello");

  const onClick = () => {
    setState("world");
    console.log(state);
    window.open("tab.html");
  };

  const onMessageReceivedFromIframe = React.useCallback(
    event => {
      console.log("onMessageReceivedFromIframe", state, event);
    },
    [state]
  );

  useEffect(() => {
    window.addEventListener("message", onMessageReceivedFromIframe);
    return () =>
      window.removeEventListener("message", onMessageReceivedFromIframe);
  }, [onMessageReceivedFromIframe]);

  React.useEffect(() => {
    console.log("state", state);
  }, [state]);

  return <button onClick={onClick}>Click here</button>;
};

答案 1 :(得分:0)

问题出在下面的代码上

useEffect(() => {
    addIframeListener();
    return () => {
      removeIframeListener();
    };
  }, []);

自从addIframeListener内部调用removeIframeListenereffect以来,状态state正在内部使用。

将代码更改为

useEffect(() => {
    addIframeListener();
    return () => {
      removeIframeListener();
    };
  }, [state]);

如果framelistener函数使用了任何道具,请将其保留在依赖数组中,否则最终会得到旧道具。