Простая шина событий для общения между компонентами во Vue 2
2 года назад·2 мин. на чтение
Иногда нужно реализовать быстрое и простое решение для передачи данных между компонентами Vue.js.
Конечно, есть Vuex для централизованного управления состоянием. Таким образом, он может обеспечить приложению единый источник истины.
Но для приложения с простой архитектурой достаточно общаться между компонентами с помощью событий. Для этого мы можем создать быстрое решение и реализовать шину событий (event bus). Шину событий позволяет нам отправлять в одном компоненте и слушать это событие в другом.
В данном примере будет показано, как это сделать в приложении Vue.js. Благодаря простоте фреймворка Vue он позволяет нам создать механизм обмена событиями с помощью нескольких строк кода.
Здесь у нас есть компонент ComponentA, который импортирует
Здесь мы создали JavaScript ES6 модуль, который импортирует Vue, создали и экспортировали новый экземпляр Vue. Вот и все. Мы реализовали EventBus и теперь можем начать его использовать.// eventBus.js import Vue from "vue"; export const eventBus = new Vue();
eventBus
. Когда вызывается метод emitMethod()
компонента, он испускает новое событие с именем EVENT_NAME
и передает вместе с ним данные события (payload).
В другом компоненте мы можем зарегистрировать слушателя, который слушает событие// ComponentA.js <script> import { eventBus } from "./eventBus"; export default { name: "ComponentA", methods: { emitMethod() { eventBus.$emit("EVENT_NAME", { data: "someData" }); }, }, }; </script> <template> <p>ComponentA</p> </template>
EVENT_NAME
, передаваемое по шине eventBus
. Как только событие появится, мы можем выполнить JavaScript с полученным в качестве аргумента payload.
Вот и все. Вот так просто мы создали решение для передачи событий между различными частями нашего приложения.// ComponentB.js <script> import { eventBus } from "./eventBus"; export default { name: "ComponentB", mounted() { eventBus.$on("EVENT_NAME", this.handleEvent); }, beforeUnmount() { eventBus.$off("EVENT_NAME", this.handleEvent); }, methods: { handleEvent(payload) { console.log(payload); // => { data: "someData" } }, }, }; </script> <template> <p>ComponentB</p> </template>
В этом примере мы создали и реализовали механизм передачи данных между слабосвязанными компонентами. Не тратя много времени и усилий на изучение принципов Vuex, Redux или других фреймворков с неизменяемым состоянием. Это удобный способ коммуникации для более простой архитектуры. Которая впоследствии может быть усовершенствована путем внедрения какого-либо централизованного фреймворка управления состояниями по мере роста приложения.// App.js <script> import ComponentA from "./ComponentA"; import ComponentB from "./ComponentB"; export default { name: "App", components: { ComponentA, ComponentB, }, }; </script> <template> <div> <ComponentB /> <ComponentA /> </div> </template>
Хорошие практики и шаблоны проектирования для Vue Composables
год назад·1 мин. на чтение
Composables (composition API) можно использовать для хранения основной бизнес-логики (например, вычислений, действий, процессов), поэтому они являются важной частью приложения. К сожалению, в командах не всегда есть соглашения для написания composables.
Эти соглашения важны для того, чтобы компоненты были удобными в обслуживании, легко тестируемыми и действительно полезными.
Общие шаблоны проектирования
На мой взгляд, лучшим источником информации о шаблонах для создания composables на самом деле является документация Vue.js, с которой вы можете ознакомиться здесь.Базовый composable
В документации Vue показан следующий пример компонуемогоuseMouse
:
Позже это можно использовать в компоненте следующим образом:// mouse.js import { ref, onMounted, onUnmounted } from 'vue' // по соглашению имена composable функций начинаются с "use" export function useMouse() { // состояние инкапсулировано и управляется самим composable const x = ref(0) const y = ref(0) // composable может обновлять состоянием function update(event) { x.value = event.pageX y.value = event.pageY } // composable также может иметь доступ к жизненному циклу родительского компонента // для установки и очистки эффектов onMounted(() => window.addEventListener('mousemove', update)) onUnmounted(() => window.removeEventListener('mousemove', update)) // отдаем состояние наружу как возвращаемое значение return { x, y } }
<script setup> import { useMouse } from './mouse.js' const { x, y } = useMouse() </script> <template>Mouse position is at: {{ x }}, {{ y }}</template>
Асинхронные composables
Для получения данных Vue рекомендует следующую компонуемую структуру:Затем это можно использовать в компоненте следующим образом:import { ref, watchEffect, toValue } from 'vue' export function useFetch(url) { const data = ref(null) const error = ref(null) watchEffect(() => { // обнуляем состояние перед запросом data.value = null error.value = null // toValue() разворачивает потенциальные рефы или геттеры fetch(toValue(url)) .then((res) => res.json()) .then((json) => (data.value = json)) .catch((err) => (error.value = err)) }) return { data, error } }
<script setup> import { useFetch } from './fetch.js' const { data, error } = useFetch('...') </script>
Соглашения composable
Основываясь на приведенных выше примерах, вот контракт, которому должны следовать все composables:- Имена composable файлов должны начинаться с
use
, напримерuseSomeAmazingFeature.ts
- Он может принимать входные аргументы, которые могут быть примитивными типами, такими как строки, или может принимать ссылки и геттеры, но для этого требуется использовать вспомогательное средство
toValue
- Composable должен возвращать значение
ref
, к которому можно получить доступ после деструктурирования composable, напримерconst { x, y } = useMouse()
- Composables могут содержать глобальное состояние, к которому можно получить доступ и изменить в приложении.
- Composable может вызвать побочные эффекты, такие как добавление прослушивателей событий окна, но их следует очищать при отключении компонента.
- Composables следует вызывать только в
<script setup>
или в хукеsetup()
. В этих контекстах их также следует называть синхронно. В некоторых случаях их также можно вызывать в обработчиках жизненного цикла, таких какonMounted()
- Composables могут вызывать другие composables внутри
- Composables должны заключать в себе определенную логику, а когда они слишком сложны, их следует извлекать в отдельные composables для облегчения тестирования.