-
iframe communication quick startJS & TS 2023. 2. 24. 23:44
목차
- 아이프레임이란 무엇인가요?
- 아이프레임으로 무엇을 할 수 있을까요?
- TODO
- 전략
- 실전
- 결과 보기
아이프레임이란 무엇인가요?
An iframe (short for "inline frame") is an HTML element that allows you to embed another HTML document or webpage within your current webpage. It creates a frame or window within your webpage that can display content from a different source, such as a different website, another webpage on your own site, or even a separate part of the same webpage.
아이프레임은 HTML 엘리먼트로 다른 HTML 다큐먼트 또는 웹페이지를 당신의 현재 웹페이지에 임베드할 수 있도록 만들어줍니다. 아이프레임은 프레임 또는 윈도우를 만들어 다른 웹사이트 또는 당신이 소유한 다른 웹사이트 심지어 같은 웹페이지의 다른 부분까지 화면에 표시할 수 있도록 해줍니다.
아이프레임으로 무엇을 할 수 있을까요?
Here are some things you can do with an iframe:
- Embedding content from other websites: You can use an iframe to embed content from another website, such as a video, map, or social media post, directly into your own webpage.
- Displaying a portion of another webpage: You can use an iframe to display a portion of another webpage, such as a specific section or article.
- Creating an inline image gallery: You can use an iframe to create an image gallery that displays a set of images within your webpage.
- Creating a website preview: You can use an iframe to create a website preview widget that allows users to preview a website before clicking on a link.
- Embedding external applications: You can use an iframe to embed external applications, such as a chat widget or a payment gateway, within your website.
아이프레임으로 할 수 있는 일들이 있습니다
- 다른 웹사이트로부터의 컨텐츠를 임베딩할 수 있습니다
- 다른 웹페이지의 일부분을 표기하기
- 인라인 이미지 갤러리 만들기
- 웹사이트 프리뷰 만들기
- 외부 어플리케이션 임베딩하기
TODO
두 가지 웹사이트를 아이프레임을 통해 소통할 수 있도록 만들기
- localhost:3000 (부모 웹 사이트)
- localhost:3001 (자식 웹 사이트)
전략
- 부모 웹 사이트(3000)에서 자식 웹 사이트(3001)를 아이프레임을 통해 임베딩합니다
- 부모 웹 사이트(3000)에서 자식 웹 사이트(3001)에 특정 함수를 통해 값 또는 함수를 전달합니다
- 자식 웹 사이트(3001)에서 부모(3000)의 메시지를 받아 상태를 업데이트합니다
- 자식 웹 사이트(3001)에서의 업데이트된 상태 값을 다시 부모(3000)에게 전달합니다
- 부모 웹 사이트(3000)에서 자식 웹 사이트(3001)로부터 온 상태 값을 화면에 렌더링 합니다
부모가 자식에게 값 전달하기
부모 웹 사이트가 자식 웹사이트에게 아이프레임을 통해 값을 전달하기 위해서 우리는 postMessage라는 메서드를 사용해야 합니다.
const iframe = document.getElementById('my-iframe'); iframe.contentWindow.postMessage('Hello from parent!', '*');
자식에서 부모의 값 받기
아이프레임은 부모로부터 전달된 postMessage를 window.addEvenListener(’message’) 이벤트를 통해 전달받을 수 있습니다.
window.addEventListener('message', function(event: MessageEvent) { if (event.origin !== '<https://parentpage.com>') return; console.log('Received message in iframe:', event.data); });
실전
아이프레임을 통해 값을 전달하더라도 리액트는 리렌더링이 발생하지 않습니다. 리렌더링을 하기 위해서는 상태 값을 변경해줘야 합니다. 이를 확인하기 위해 직접 코드를 구현해 보도록 하겠습니다.
(A) child component - iframe embeded (localhost:3001/test)
$ npx create-next-app child --typescript
import React, { useEffect, useState } from 'react'; const Test = () => { const [counter, setCounter] = useState(0); useEffect(() => { window.addEventListener('message', handleMessage); return () => { window.removeEventListener('message', handleMessage); }; }, []); const handleMessage = (event) => { if (event.data.type === 'plusCounter') { setCounter((prev) => prev + event.data.payload); } else if (event.data.type === 'minusCounter') { setCounter((prev) => prev - event.data.payload); } }; const doSomething = () => { window.parent.postMessage(counter, '*'); }; return ( <> <span style={{ marginRight: 10 }}>Counter: {counter}</span> <button type='button' onClick={doSomething}> submit current state </button> </> ); }; export default Test;
- useState를 통해 counter, setCounter를 초기화합니다
- useEffect 함수를 통해 처음 마운트될 때 ‘message’ 이벤트를 읽을 수 있도록 구독처리합니다
- handleMessage는 ‘message’ 이벤트가 발생했을 때 호출할 함수입니다
- 부모 컴포넌트에서 event.data를 값으로 간단히 보내는 대신 객체로 보내 type에 따라 counter를 업데이트할 수 있도록 만듭니다
- type은 총 두 가지입니다
- updateCounter - 이전 counter 변수에 event.data.payload를 더합니다
- minusCounter - 이전 counter 변수에 event.data.payload를 뺍니다
- 버튼을 클릭할 경우 doSomething 함수를 호출합니다
- doSomething 함수는 저장하고 있는 최신의 counter state를 부모에게 전달하는 역할을 합니다
- 부모 컴포넌트에게 메시지를 전달하는 방법은 window.parent.postMessage() 메서드를 사용합니다
targetWindow.postMessage(message, targetOrigin, [transfer]);
targetWindow
메세지를 전달받을 window의 참조. 참조를 취득할 방법으로는 다음과 같은 것이 있습니다:
* Window.open (새 창을 만들고 새 창을 참조할 때)
• Window.opener (새 창을 만든 window를 참조할 때)
• HTMLIFrameElement.contentWindow (부모 window에서 임베디드 된 <iframe>을 참조할 때)
• Window.parent (임베디드 된 <iframe>에서 부모 window를 참조할 때)
(B) parent component that use ifrmae (localhost:3000)
$ npx create-next-app parent --typescript
import React, { useCallback, useEffect, useRef, useState } from 'react'; const Parent = () => { const [parentCounter, setParentCounter] = useState(0); const iframeRef = useRef<HTMLIFrameElement>(null); const receiveMessage = useCallback((event: MessageEvent<any>) => { if (!event.origin.includes('<http://localhost:3001>')) return; setParentCounter(event.data); }, []); const handleButtonClick = () => { if (!iframeRef.current || !iframeRef.current.contentWindow) return; const message = { type: 'plusCounter', payload: 1, }; iframeRef.current.contentWindow.postMessage(message, '*'); }; const handleMinusButtonClick = () => { if (!iframeRef.current || !iframeRef.current.contentWindow) return; const message = { type: 'minusCounter', payload: 1, }; iframeRef.current.contentWindow.postMessage(message, '*'); }; useEffect(() => { window.addEventListener('message', receiveMessage, false); return () => { window.removeEventListener('message', receiveMessage, false); }; }, [receiveMessage]); return ( <div> <button type='button' onClick={handleButtonClick}> + </button> <button type='button' onClick={handleMinusButtonClick}> - </button> <h1>Editor</h1> <iframe ref={iframeRef} src='<http://localhost:3001/test>' style={{ margin: 0, border: '2px solid', width: '100%', height: '80vh', boxSizing: 'border-box', }} /> {parentCounter ? <span>Parent counter is {parentCounter}</span> : null} </div> ); }; export default Parent;
- 자식에게 전달받은 counter 상태값을 저장할 useState를 초기화합니다 (parentCounter)
- 아이프레임의 DOM에 직접 접근하기 위해 useRef를 초기화합니다 (iframeRef)
- 자식으로부터 message를 넘겨받을 때 호출할 함수를 정의합니다 (receiveMessage)
- 부모에서 자식으로 보낼 postMessage를 정의합니다 (handleButtonClick, handleMinusButtonClick)
- 마운트 이후 message 이벤트를 받을 수 있도록 useEffect 내부에 window.addEventListener를 선언합니다
- 각 버튼에 선언한 버튼을 연결합니다 (+), (-)
- 아이프레임에 useRef 및 자식 컴포넌트인 자식 페이지를 연동합니다
- parentCounter 가 falsy 값이 아닐 경우, 화면에 렌더링 합니다 (parentCounter)
결과 보기
'JS & TS' 카테고리의 다른 글
REST API 바로 알기 (0) 2022.10.23 프로미스(Promise) 바로 알기 (0) 2022.10.22 이벤트 루프 동작 원리 (0) 2022.10.20 리팩터링 - Guard Clause를 사용하여 코드 가독성 높히기 (0) 2022.09.13 모바일 기기를 체크하여 크로스 브라우징 지원하기 (navigator.userAgent 사용하기) (0) 2022.08.25