В прошлом уроке мы с вами разобрали, как чайлд компоненты можно обмениваться данными между собой с помощью парента. Это отлично работает и легко дебажится, но нам приходится писать намного больше кода, чем если бы они взаимодействовали напрямую без парента.
В Vue есть встроенный publish subscribe паттерн, который позволяет нам передавать данные между любыми компонентами. Очень часто его еще называют event bus.
На данный момент у нас есть парент App компонент и 2 child компоненты LoginForm и SuccessMessage.
Давайте порефакторим эти компоненты, чтобы убрать необходимость передавать данные через parent.
Было бы замечательно, чтобы в любом компоненте мы могли импортировать eventBus в таком стиле
import {eventBus} from './main'
И чтобы eventBus уже содержал нужные методы для подписки и отправки евентов.
Для этого достаточно инициализировать новый экземпляр Vue, так как методы для publish subscribe лежат в руте инстанса Vue.
main.js
export const eventBus = new Vue()
new Vue({
el: '#app',
render: h => h(App)
})
Теперь мы можем импортировать eventBus в LoginForm, как я показывал ранее.
LoginForm.vue
import {eventBus} from './main'
...
Теперь нам достаточно изменить this.$emit на eventBus.$emit. Он будет работать абсолютно в таком же виде, но содержать всех подписчиков не в компоненте, а внутри обьекта eventBus. Именно поэтому нам не нужны другие компоненты для взаимодействия.
LoginForm.vue
eventBus.$emit('login', {
email: this.email,
password: this.password
})
Теперь мы хотим подписаться в компоненте SuccessMessage на событие login. Сначала мы должны импортировать eventBus, как мы делали с LoginForm.
SuccessMessage.vue
import {eventBus} from './main'
Теперь мы должны подписаться на евент login.
У каждого компонента есть специальный хук created, внутри которого мы можем написать какой-то код, и он сработает, когда этот компонент создастся.
Давайте попробуем добавить created в SuccessMessage.
SuccessMessage.vue
export default {
...
created () {
console.log('component was created')
}
}
Если мы посмотрим в браузер, то у нас вывелось сообщение created. Теперь мы можем подписаться на наш евент login внутри него и тогда при создании компонента мы всегда будет подписываться на этот евент.
SuccessMessage.vue
data () {
return {
email: ''
}
},
created () {
eventBus.$on('login', data => {
this.email = data.email
})
}
Здесь мы использовали $on метод из eventBus. Первым аргументом мы передаем название евента, который мы хотим слушать, в нашем случае, это login. Вторым аргументом мы передаем callback, который произойдет, когда этот евент сработает. Первым параметром этот коллбека мы получаем данные, которые мы передали из LoginForm компонента. После чего мы просто обновляет локальную переменную email у компонента.
Если мы посмотрим в браузер, то все работает как и раньше.
Подход с eventBus очень легкий в использовании, но может быть сложным в поддержке, когда у нас огромное количество евентов в приложении и каждый компонент может поменять самого себя слушая какой-то евент. Именно поэтому его нужно применять с осторожностью. Подход с передачей данных через parent компонент намного легче дебавижить, по сравнению с eventBus, но мы пишем больше кода.
Также, есть другой способ передачи данных между компонентами с помощью библиотеки Vuex, но ее мы с вами разберем позже.
Если у вас возникли какие-то вопросы или комментарии, пишите их прямо под этим видео.