Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React hooks change the state on postMessage

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.

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.

like image 618
Paz Lazar Avatar asked Aug 01 '19 07:08

Paz Lazar


People also ask

How do I change the state in React Hooks?

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) .

Can React Hooks have state?

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.

Do Hooks share state between components?

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.

Can you initialize state from a function in React Hooks?

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.


1 Answers

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>;
};
like image 115
Prithwee Das Avatar answered Oct 19 '22 12:10

Prithwee Das