멀리 떨어져있는 컴포넌트들 간의 통신이 필요할 때 컴포넌트 계층간에 전부 emit해주기는 많이 번거로운데, 대안으로 Vue2에서는 EventBus를 사용할 수 있었지만 Vue3에서는 다른 방안을 찾아야 한다.
1. Composition API를 사용하지 않는 경우
main.js에서 app을 마운트 하기 전, app의 `config.globalProperties`에 등록하여 `this.{변수명}` 형태로 불러오는 경우가 일반적이다.
MyComponent.js
<script>
export default defineComponent({
name: 'MyComponent',
components: {},
setup() {},
data() {},
mounted() {},
methods: {}
});
</script>
<template>
...
</template>
기본적으로 위와 같은 구조를 가지고 있을 것이다. 이럴 경우에 methods 내부에 정의한 메서드에서 mitt를 사용해야 한다면 아래와 같이 작성할 수 있다.
mitt를 글로벌 프로퍼티로 등록(main.js)
import App from './App.vue';
import mitt from 'mitt';
let emitter = mitt();
const app = createApp(App);
app.config.globalProperties.emitter = emitter;
app.mount('#app');
emit 전송부(MyComponent.js)
methods: {
myFunction() {
this.emitter.emit('emit-name', {data: 'emit!'});
}
}
emit 수신부(TargetComponent.js)
mounted() {
this.emitter.on('emit-name', (param) => {
console.log(param.data);
});
}
Vue3에 들어와서 Composition API가 도입됨에 따라 setup 스크립트를 사용할 수 있게 되었는데, 이 경우에는 `<script setup>` 내부에서 this를 통해 globalProperties를 불러오지 못한다.
2. Composition API를 사용하는 경우(중에서도 setup script를 사용할 경우)
mitt를 inject할 수 있는 상태로 제공(main.js)
import App from './App.vue'
import mitt from 'mitt';
let emitter = mitt();
const app = createApp(App);
app.provide('emitter', emitter);
app.mount('#app');
MyComponent.js
<script setup>
import {inject} from 'vue';
const emitter = inject('emitter');
</script>
<template>
...
</template>
Cf. provide() 되는 객체를 불러와도 제대로 작동하지 않을 경우
내 경우에는 `inject('emitter')`로 mitt 객체를 주입시켜 사용하려했다. 그러나 디버그할 당시 객체 정보가 안들어있는건 아닌데, `emit`은 되면서 `on`에서 받지 못하는 문제가 발생했다.
결국에는 `mitt()`를 반환해주는 모듈로 만들어, 필요할 때마다 import 해서 사용하고 있다.
emitter.js
import mitt from 'mitt';
export default mitt();
Cf. 참고 링크