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);
};
}, []);
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}
/>
);
};
최대 열번까지 재호출 하도록 하였고, 이렇게 수정하고 나니 문제가 없어져 고통에서 해방될 수 있었다.