admin管理员组文章数量:1291145
I have a ponent with some state using useState
.
This ponent opens a new tab and should receive a message event on postMessage. For some reason, after I get the event, the state returns to its initial state.
I tried saving the state to localStorage and it worked.
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", "");
window.close();
}, 2000);
</script>
</body>
</html>
The state returns to its initial state.
A demo can be seen here:
BTW:
I know that the event is not fired from tab.html
but there is still an event that fires on tab opening.
I have a ponent with some state using useState
.
This ponent opens a new tab and should receive a message event on postMessage. For some reason, after I get the event, the state returns to its initial state.
I tried saving the state to localStorage and it worked.
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>
The state returns to its initial state.
A demo can be seen here: https://codesandbox.io/s/trusting-waterfall-9jzj7
BTW:
I know that the event is not fired from tab.html
but there is still an event that fires on tab opening.
2 Answers
Reset to default 5seems your problem was with the deps array of your effect hook, and onMessageReceivedFromIframe
being created on every render.
the solution below should work like you expect. here is a link to the 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>;
};
The problem is with the below code
useEffect(() => {
addIframeListener();
return () => {
removeIframeListener();
};
}, []);
Since its calling addIframeListener
and removeIframeListener
from inside effect
and the state state
is getting used inside it.
Change the code as
useEffect(() => {
addIframeListener();
return () => {
removeIframeListener();
};
}, [state]);
If there is any props getting used by framelistener
function, keep that in dependent array otherwise you will end up getting old props
本文标签: javascriptReact hooks change the state on postMessageStack Overflow
版权声明:本文标题:javascript - React hooks change the state on postMessage - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741498316a2381936.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论