dkmqflx's blogGithub

Broadcastchannel API로 서로 다른 탭 사이에 통신하기

2022.11.10

들어가며

개발을 진행하다보면 다른 탭 사이에 데이터를 전달해야 하는 경우가 있다. 예를들어 새로운 탭을 열고 해당 탭에 이전 탭에의 데이터를 전달하는 경우이다.

해결방법으로는 여려가지가 있을 수 있겠으나 그 중에서도 BroadcastChannel을 사용하면 다른 탭 사이의 데이터 전송을 손 쉽게 구현할 수 있다.


BroadcastChannel

BroadcastChannel은 동일한 Origin을 가진 서로 다른 브라우저 창, 탭, iframe 간 통신을 가능하게 해주는 브라우저 API이다.

이는 복잡한 메시지 전송 메커니즘을 단순화하여 다중 탭이나 창 간에 데이터를 손쉽게 주고받을 수 있도록 한다.

아래는 BroadcastChannel 객체를 생성하는 방법이다.

const broadcastChannel = new BroadcastChannel(CHANNEL_NAME);

CHANNEL_NAME은 통신에 사용될 채널의 이름이며, 동일한 Origin에서는 동일한 이름의 BroadcastChannel이 공유된다. 따라서 중복된 이름으로 여러 BroadcastChannel을 생성하더라도 동일한 채널로 간주된다..

생성된 BroadcastChannel 객체는 postMessage 메서드를 통해 메시지를 전송할 수 있다.

이 메시지는 같은 이름의 BroadcastChannel을 리스닝하고 있는 모든 인스턴스에 전달된다.

const sendBroadcastChannel = new BroadcastChannel(CHANNEL_NAME);
sendBroadcastChannel.postMessage("new Message!");

전달된 메시지는 아래와 같이 동일한 CHANNEL_NAME을 사용하는 다른 BroadcastChannel 객체에서 수신할 수 있으며, onmessage 이벤트를 통해 접근 가능하다.

const receiveBroadcastChannel = new BroadcastChannel(CHANNEL_NAME);
 
receiveBroadcastChannel.onmessage = (event) => {
  console.log(event.data); //  'new Message!'
};

이처럼 BroadcastChannel은 간단한 API로 탭 간 통신을 손쉽게 구현할 수 있다.

브라우저에서 기본적으로 제공하는 API이므로 별도의 라이브러리 없이도 사용할 수 있다는 장점이 있다.


React에서 BroadcastChannel을 사용하는 Custom Hook 만들기

React 환경에서도 BroadcastChannel을 활용하여 다중 탭 간 통신을 구현할 수 있다.

아래는 React에서 사용할 수 있는 BroadcastChannel용 Custom Hook의 구현한 코드이다.

// hooks/useBroadCastChannel.jsx
 
import { useEffect, useRef, useState } from "react";
 
const CHANNEL_NAME = "newtab";
 
const useBroadCastChannel = () => {
  const channel = useRef(null);
  const [data, setData] = useState(null);
 
  // 메시지를 보내는 함수
  const postMessage = (message) => {
    channel.current?.postMessage(message);
  };
 
  // 새로운 탭을 여는 함수
  const openNewTab = () => {
    window.open("/newtab", "_blank");
  };
 
  useEffect(() => {
    channel.current = new BroadcastChannel(CHANNEL_NAME);
 
    // 메시지 이벤트 리스너 등록
    const messageHandler = (event) => {
      setData(event.data);
    };
    channel.current.addEventListener("message", messageHandler);
 
    return () => {
      // 메시지 이벤트 리스너 해제
      channel.current?.removeEventListener("message", messageHandler);
    };
  }, []);
 
  return { postMessage, data, openNewTab };
};
 
export default useBroadCastChannel;

위 코드의 Custom Hook의 주요 기능을 정리하자면 다음과 같다

  1. postMessage: 메시지를 지정된 BroadcastChannel로 전송한다.

  2. data: 메시지 이벤트가 발생할 때 수신된 데이터를 상태로 저장한다.

  3. openNewTab: 새로운 탭을 열어 /newtab 경로를 표시한다.


Custom Hook 사용 예제

아래는 위에서 정의한 useBroadCastChannel Hook을 활용하여 다중 탭 간 메시지를 송수신하는 예제이다.

Home 컴포넌트는 새로운 탭에서 보낸 메시지를 수신하여 화면에 표시한다.

// pages/Home.js
import useBroadCastChannel from "@/src/hooks/useBroadCastChannel";
 
export default function Home() {
  const { data, openNewTab } = useBroadCastChannel();
 
  return (
    <div>
      <div>Received Data: {data || "No data yet"}</div>
      <button onClick={openNewTab}>Open New Tab</button>
    </div>
  );
}

newtab 컴포넌트는 메시지를 입력받아 기존 탭으로 전달한다.

// pages/newtab.jsx
import useBroadCastChannel from "@/src/hooks/useBroadCastChannel";
 
const NewTab = () => {
  const { postMessage } = useBroadCastChannel();
 
  const onSubmit = (e) => {
    e.preventDefault();
    const message = e.target.data.value;
    postMessage(message);
  };
 
  return (
    <form onSubmit={onSubmit}>
      <input type="text" name="data" placeholder="Enter message" />
      <button type="submit">Send</button>
    </form>
  );
};
 
export default NewTab;

위 코드가 동작하는 방법을 정리하자면 다음과 같다

  1. Home에서 Open New Tab 버튼 클릭: 새로운 탭(/newtab)이 열린다.

  2. 새로운 탭에서 메시지 전송: 폼에 데이터를 입력하고 전송 버튼을 누르면 메시지가 BroadcastChannel을 통해 전달된다.

  3. Home에서 메시지 수신: 전달된 메시지가 실시간으로 화면에 표시된다.