본문 바로가기

Vue.js

[Vue.js] Vue.js에서 BroadcastChannel 사용법: 실시간 데이터 동기화하기

최근 프로젝트에서 기획자분이 한 사용자가 같은 컴퓨터에서 여러 개의 브라우저 탭을 열어놓고 작업할 때, 'A' 탭에서 데이터를 변경하거나 어떤 처리를 했을 경우, 다른 탭('B' 탭)에 변경 사항이 즉시 반영되지 않는 문제를 해결해달라고 찾아왔다.

이 문제는 사용자 경험에 큰 영향을 미칠 수 있는 상황으로, 웹서비스가 관리자페이지이다보니 실시간 데이터 동기화가 중요한 서비스에서 반드시 해결해야 할 과제였다. 이번 글에서는 문제의 원인을 분석하고, 이를 해결하기 위해 어떤 접근 방식을 사용했는지 공유하고자 한다.

 

 

 

 

 


 

 

 

서론


ATab, BTab 이 있는 상황에서 ATab이 로그아웃 할 경우 브라우저 내의 토큰을 제거하는 로직이 이미 구현되어 있었다.

하지만 이렇게 할 경우 BTab 에선 ATab 에서 일어난 로그아웃 이벤트가 전달되지 않았다 (cookie 나 storage에 토큰 제거 되어있는 상태)

그래서 로그인 되어 있는거 같은 화면에서 새로고침을 해야 하는 상황인데

VueUse 의 BroadcastChannel API 를 사용해서 해결하였다. (원래는 web 안에 iframe 과의 통신을 할 때 사용했던 것으로 알고 있었음.)

해당 채널을 만들고 post 함수와 함께 특정 값을 넣어 실행 시켜주면 다른 탭에서도 적용된걸 확인할 수 있다.

 

 

 

문제 정의


'A' Tab에서 데이터를 변경하거나 어떤 처리를 했을 경우 다른 탭('B' Tab)에 적용이 안되는 문제

 

 

 

 

원인 분석


실시간 데이터 동기화를 구현이 필요

 

 

 

해결 방법


프로젝트에서 A탭에서 로그아웃 하고 다른 계정으로 로그인 했을 때 B탭에도 이를 동기화 하는 방법

👉 Vue.js에서 BroadcastChannel API를 도입하여 실시간 데이터 동기화를 구현해보기로 했다.

 

 

 

 

참고 링크

https://vueuse.org/core/useBroadcastChannel/#usebroadcastchannel

 

VueUse

Collection of essential Vue Composition Utilities

vueuse.org

https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel

 

BroadcastChannel - Web APIs | MDN

The BroadcastChannel interface represents a named channel that any browsing context of a given origin can subscribe to. It allows communication between different documents (in different windows, tabs, frames or iframes) of the same origin. Messages are bro

developer.mozilla.org

 

 

 

 

 

이 문제를 해결하기 위해 로그아웃 기능에 BroadcastChannel API를 적용했다. 이를 통해 한 탭에서 로그아웃을 수행하면 다른 모든 탭에서도 자동으로 로그아웃이 이루어지도록 구현했다. 아래는 그 구현 코드이다:

 

적용 결과

// 로그아웃에 적용


<template>
    <q-list>
      <q-item clickable v-close-popup>
        <q-item-section @click="handleClickLogout">
          <q-item-label>로그아웃</q-item-label>
        </q-item-section>
      </q-item>
    </q-list>

</template>

<script lang="ts">
import { computed, defineComponent, watchEffect } from 'vue'
import { useBroadcastChannel } from '@vueuse/core'
import { useAuthStore } from '@/stores'

...

export default defineComponent({
  setup() {
    const authStore = useAuthStore()
    const router = useRouter()

    const { data, post } = useBroadcastChannel({ name: '####' })

    watchEffect(async () => {
      if (data.value === 'logout') {
        await authStore.logout()
        await router.push('/login')
      }
    })

    return {
      handleClickLogout: async () => {
        post('logout')
        await authStore.logout()
        await router.push('/login')
      },
    }
  },
})


</script>

 

코드 설명

템플릿 부분:

▫️q-list와 q-item을 사용하여 로그아웃 버튼을 생성합니다.
▫️q-item-section에 @click 이벤트를 추가하여 handleClickLogout 메서드를 호출합니다.


스크립트 부분:

▫️ useBroadcastChannel을 사용하여 auth-channel이라는 이름의 BroadcastChannel을 생성합니다.
▫️ watchEffect를 사용하여 data 값이 'logout'으로 변경되면 authStore.logout()을 호출하고 로그인 페이지로 리디렉션합니다.
▫️ handleClickLogout 메서드는 로그아웃 버튼 클릭 시 호출되며, BroadcastChannel을 통해 'logout' 메시지를 전송하고, 현재 탭에서도 로그아웃을 수행합니다.


 

 

 

 

 

 

결론


이와 같이 BroadcastChannel API 사용하여 여러 간의 상태 동기화를 구현함으로써, 탭에서 로그아웃을 수행하면 다른 모든 탭에서도 자동으로 로그아웃이 이루어지도록 있다.

VueUse에 다향한 유틸리히 훅들있어서 코드작성이 훨씬 간단해지고, 웬만한 기능들은 잘 찾아보면 있는 것 같다 VueUse 를 적극 활용해서 해결하면 좋을 것 같다 !

 

 

728x90
반응형