Dependency Injection (DI) — это шаблон проектирования, который позволяет передавать зависимости в компоненты, вместо того чтобы компоненты сами их создавали. Во Vue.js DI используется для управления состоянием, сервисами, утилитами и другими объектами, которые могут понадобиться различным компонентам без прямого связывания их с конкретными реализациями.
Инверсия управления Компонент не создает свои зависимости, а получает их извне. Это повышает тестируемость и переиспользуемость кода.
Область видимости В Vue.js зависимости можно предоставлять на уровне всего приложения или ограничивать определенным компонентом и его потомками.
Декларативность Vue предлагает декларативный
синтаксис через provide и inject, который
упрощает передачу данных вниз по иерархии компонентов.
Метод provide позволяет компоненту “предоставить”
значения, которые могут быть использованы дочерними компонентами. Обычно
используется в корневом или промежуточном компоненте.
export default {
name: 'ParentComponent',
provide() {
return {
apiService: new ApiService(),
config: { theme: 'dark' }
};
},
template: `<ChildComponent />`
}
provide возвращает объект, где ключи — имена
зависимостей, а значения — сами объекты или функции.Дочерние компоненты получают зависимости с помощью
inject.
export default {
name: 'ChildComponent',
inject: ['apiService', 'config'],
mounted() {
console.log(this.apiService, this.config);
},
template: `<div>Child Component</div>`
}
inject указывает имена зависимостей, которые были
предоставлены родителем.provide может быть функцией, возвращающей объект. Это
позволяет динамически формировать зависимости, основанные на состоянии
компонента.
export default {
data() {
return {
theme: 'light'
};
},
provide() {
return {
config: { theme: this.theme }
};
}
}
Изменения theme после инициализации компонента
не будут автоматически отражены в дочерних компонентах,
так как provide выполняется один раз при создании
экземпляра. Для реактивных зависимостей нужно использовать Vue
reactive:
import { reactive, provide } from 'vue';
export default {
setup() {
const config = reactive({ theme: 'light' });
provide('config', config);
return { config };
}
}
Теперь любые изменения config.theme будут автоматически
доступны дочерним компонентам.
DI особенно полезна для внедрения сервисов:
class ApiService {
fetchData() {
return fetch('/api/data').then(res => res.json());
}
}
export default {
setup() {
const apiService = new ApiService();
provide('apiService', apiService);
}
}
Дочерний компонент может использовать этот сервис без создания собственного экземпляра:
import { inject } from 'vue';
export default {
setup() {
const apiService = inject('apiService');
apiService.fetchData().then(data => console.log(data));
}
}
Локальная область видимости inject
работает только с родительскими компонентами в цепочке вверх.
Зависимости не передаются в глобальные компоненты
автоматически.
Реактивность Простые объекты, переданные через
provide, не являются реактивными. Для реактивных значений
использовать reactive или ref.
Тестируемость DI упрощает подмену сервисов при
тестировании. В тестах можно создать заглушку и передать её через
provide.
Составные компоненты В больших приложениях DI помогает снизить связанность компонентов и улучшить масштабируемость архитектуры.
Если требуется глобальное состояние и сложная логика управления
зависимостями, DI можно сочетать с Pinia или
Vuex, предоставляя состояние через
provide, но управляя его изменениями централизованно. Такой
подход сохраняет модульность, избегая жесткой привязки к конкретной
реализации состояния.
Dependency Injection в Vue.js обеспечивает чистую архитектуру,
повышает переиспользуемость компонентов и улучшает поддержку крупных
приложений. С правильным использованием provide и
inject можно легко управлять зависимостями на всех уровнях
и создавать реактивные и модульные решения.