provide и inject
↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая
Зачем это на собесе
Аналог DI во Vue: передача данных через несколько уровней без prop drilling.
Объяснение
// Предок (или app.provide на уровне приложения)
const theme = ref<"light" | "dark">("light");
const toggle = () => (theme.value = theme.value === "light" ? "dark" : "light");
provide(ThemeKey, { theme: readonly(theme), toggle }); // отдаём readonly + функция изменения
// Потомок (любой глубины)
const ctx = inject(ThemeKey); // может быть undefined
const safe = inject(ThemeKey, defaultValue); // значение по умолчанию
const strict = inject(ThemeKey) ?? (() => { throw new Error("ThemeProvider missing"); })();Типизированный ключ:
import type { InjectionKey, Ref } from "vue";
interface ThemeContext { theme: Readonly<Ref<"light" | "dark">>; toggle(): void }
export const ThemeKey: InjectionKey<ThemeContext> = Symbol("theme");Применения: темы, i18n, контекст формы (FormItem находит Form), UI-библиотеки (Quasar/Element используют внутри), плагины (app.provide), внедрение сервисов (API-клиент) и тестовых подстановок.
Реактивность: передавайте ref/computed; изменения выполняйте через функции, переданные вместе (единый источник изменений — у поставщика).
Сравнение способов передачи данных:
| Способ | Когда |
|---|---|
| Props/emits | родитель–потомок, явный контракт |
provide/inject | сквозная передача, контекст компонентного дерева |
| Pinia | глобальное состояние приложения |
| Event bus | не рекомендуется |
Нюансы и подводные камни
- Неявные зависимости усложняют чтение: документируйте ключи и используйте типизацию.
- Потомок не должен мутировать инжектируемые данные напрямую.
injectработает только вsetup(или черезapp.runWithContext).- Ключ-строка может конфликтовать: используйте
Symbol. - Компонент, использующий
inject, тяжелее тестировать: передавайте контекст черезglobal.provide.
Практика
- Создайте
ThemeProviderсprovideиuseTheme()composable. - Реализуйте контекст формы для вложенных полей.
- Подмените контекст в тесте.
Вопросы с ответами
Когда
provide/inject, а когда Pinia?
provide/inject— контекст поддерева компонентов; Pinia — глобальное состояние приложения с DevTools и логикой.
Как сохранить реактивность при
provide?Передавать
ref/computed, а не примитивные значения.