Iframe PostMessage 타이밍 이슈 수정

IT공부중·6일 전
0

삽질

목록 보기
28/28

parent page와 iframe 에서 공유하는 데이터가 있어서, iframe이 load 될 때 postMessage로 데이터를 보내주고 있었다.
하지만 대부분의 pc에서 잘 되던 로직이 테스트 도중 몇몇 pc에서 안 된다고 하는거를 들었고 그 이슈를 해결해야 했다. 기존에 코드는 아래와 같다.

iframe 쪽 코드

useEffect(() => {
    const getData = (event: MessageEvent) => {
      if (event.origin !== environments.iframeOrigin) {
        return;
      }

      const { data } = event;

      if (data) {
        localStorage.setItem('data', data);
      }
    };

    window.addEventListener('message', getData);


    return () => {
        window.removeEventListener('message', getData);
    };
  }, []);

parent 코드

const ExamplePage = () => {
 const sendMessageToIframe = () => {
    const iframe = document.getElementById('myIframe') as HTMLIFrameElement;
    const message = { data: localStorage.getItem('data') };
   
    if (!iframe?.contentWindow) {
      return;
    }

    iframe.contentWindow.postMessage(message, config.iframe);
  };

  return (
        <iframe
          id="myIframe"
          src={'example.com'}
          title="example"
          style={{ width: '100%', height: '100%', border: 'none' }}
          onLoad={sendMessageToIframe}
        />
  );
};

버그를 수정하기 위해 Parent 쪽에서 여러번 postMessage를 보내도록 설정했고, Iframe 쪽에서 데이터를 받았다면 받았다고 다시 postMessage를 보내고, Parent에서 응답을 받고나면, postMessage를 중단하도록 추가했다.

iframe 코드

 useEffect(() => {
    const getData = (event: MessageEvent) => {
      if (event.origin !== environments.iframeOrigin) {
        return;
      }

      const { data } = event;

      if (data) {
        localStorage.setItem('data', data);

        event.source?.postMessage('data register', {
          targetOrigin: event.origin ?? '',
        });
      }
    };

     window.addEventListener('message', getData);
   

    return () => {
        window.removeEventListener('message', getDataToken);
    };
  }, []);

parent 코드

const ExamplePage = () => {
  const timeoutId = useRef<number>();
  const retry = useRef(10);

  const sendMessageToIframe = () => {
    const iframe = document.getElementById('myIframe') as HTMLIFrameElement;

    const transferData = () => {
      if (retry.current === 0) {
        alert('data transfer error');
        clearTimeout(timeoutId.current);

        return;
      }

      timeoutId.current = setTimeout(transferData, 2000) as unknown as number;

      if (!iframe?.contentWindow) {
        return;
      }

      const message = { data: localStorage.getItem('data') };
      retry.current -= 1;
      iframe.contentWindow.postMessage(message, config.iframe);
    };

    transferData();
  };

  useEffect(() => {
    window.addEventListener('message', (event) => {
      const iframeHost = new URL(config.iframe).origin;

      if (event.origin !== iframeHost) return;

      if (timeoutId.current) {
        clearTimeout(timeoutId.current);
      }
    });
  }, []);

  return (
        <iframe
          id="myIframe"
          src={config.iframe}
          title="example"
          style={{ width: '100%', height: '100%', border: 'none' }}
          onLoad={sendMessageToIframe}
        />
  );
};

최대 열번까지 재호출 하도록 하였고, 이렇게 수정하고 나니 문제가 없어져 고통에서 해방될 수 있었다.

profile
4년차 프론트엔드 개발자 문건우입니다.

0개의 댓글