I have a component with some state using useState
.
This component 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.
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"));
<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.
To update the state, call the state updater function with the new state setState(newState) . Alternatively, if you need to update the state based on the previous state, supply a callback function setState(prevState => newState) .
Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class. Read the Motivation to learn why we're introducing Hooks to React.
Sharing states We can see that Hooks states works exactly like class component states. Every instance of the component has its own state. To work a solution which shares state between components, we will create a custom Hook. The idea is to create an array of listeners and only one state object.
With React 16.8, function components can now use state. Before this, data from the state had to be passed down as props from class components to function components or you had to convert your function component to a class component. Now, we can use React hooks, and to use state we can use the useState hook.
seems 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>;
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With