EventBus 적용기

poyal·2023년 12월 1일
0
post-thumbnail

Broadcast가 왜 싫은가?

실무에서 vue를 활용한 eventbus개념을 사용허고 있었다. 이것을 broadcast라고 사용하고 있었다.
컴포넌트간의 드릴링등 여러가지의 이유가 있어서 해당개념을 사용하고 있었다.

import Vue from 'vue';

export const broadcast = new Vue();

broadcast.$emit('EVENT', message);

// on
created() {
  broadcast.$on('EVENT', callback);
}

// off
beforeDestroy() {
   broadcast.$off('EVENT');
}

간단하고 명료한 코드였지만, 사용하면서 조금씩의 불편함이 존재하고 있었다.

무엇이?

  • vue에 강력히 의존적이다.
  • 생성한 vue 객체에 $emit을 정확히 해야만 동작한다.
  • vue@3로 마이그레이션 또는 생성해야 될때, vue@3는 $on,$off가 없어져서 곤란해 진다.

이러한 이유 때문에 여러 사이트를 참고하여 eventbus를 만들어 보았다.

Broadcast에서 EventBus로

무엇을 하고 싶은지?

  • typescript만을 사용해서 언제든지 타입만 삭제하더라도 javascript로 변경할수 있어야된다.
  • class로 작성하되, 생성자를 막아서 하나의 객체만 사용하는 구조를 만든다.
  • 해당 이벤트를 구독하면 구독해제할 도구를 리턴해야 하면 좋을거같다.
  • 없는 이벤트일 때, 등록되지 않는 이벤트일 때 개발자에가 알려줄 warning이 있으면 좋을거같다.
// event-bus.handler.ts

interface Subscriber {
  event: ENUM;
  callback: (...args: any[]) => void;
}

export interface EventBusCallback {
  unsubscribe: () => void;
}

class EventBusHandler {
  static instance: EventBusHandler;

  static getInstance(): EventBusHandler {
    if (!this.instance) {
      this.instance = new EventBusHandler();
    }

    return this.instance;
  }

  private subscribers: Map<string, Subscriber> = new Map<string, Subscriber>();

  private constructor() {

  }

  dispatch(event: ENUM, ...args: any[]) {
    if (!ENUM[event]) {
      console.warn(`EventBusHandler event(${event}) not found!`);
      return;
    }

    if (!this.isExist(event)) {
      console.warn(`EventBusHandler dispatch event(${event}) not found!`);
      return;
    }

    this.subscribers.forEach((subscriber: Subscriber) => {
      if (subscriber.event === event) {
        subscriber.callback(...args);
      }
    });
  }

  subscribe(event: ENUM, callback: (...args: any[]) => void): EventBusCallback | null {
    if (!ENUM[event]) {
      console.warn(`EventBusHandler event(${event}) not found!`);
      return null;
    }

    const id: string = this.getRandomKey();
    const eventBusSubscriber: Subscriber = {
      event,
      callback
    };

    this.subscribers.set(id, eventBusSubscriber);

    return {
      unsubscribe: () => {
        this.subscribers.delete(id);
        return null;
      }
    };
  }

  private isExist(event: ENUM): boolean {
    let returnValue: boolean = false;

    this.subscribers.forEach((value: Subscriber) => {
      if (value.event === event) {
        returnValue = true;
      }
    });

    return returnValue;
  }
  
  private getRandomKey(): string {
      let result: string = '';
    const characters: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    const charactersLength: number = characters.length;

    for (let i = 0; i < 32; i++) {
      result += characters.charAt(Math.floor(Math.random() * charactersLength));
    }

    return result;
  }
}

export const eventBus: EventBusHandler = EventBusHandler.getInstance();

사용하는 방법

// 구독하는 곳
private subscriber: EventBusCallback | null = null;

created() {
  this.subscriber = eventBus.subscribe('DEFAULT', callback);
}

beforeDestroy() {
  if (!!this.subscriber) {
    this.subscriber = this.subscriber.unsubscribe();
  }
}

// 부르는 곳
eventBus.dispatch('DEFAULT', 'MESSAGE');

handler 부분의 코드는 확실히 증가하였으나, 프레임워크의 의존성이 더 낮아졌다고 생각한다.
프로젝트를 진행하다보면 여려가지의 이유로 의존성이 높아지는 코드들이 나오는데 차근차근 해결해 나가면 좋을거같다.

참조

0개의 댓글