provide и inject

↑ 4.1 Vue 3: основы, компоненты, Composition API · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Аналог 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.

Практика

  1. Создайте ThemeProvider с provide и useTheme() composable.
  2. Реализуйте контекст формы для вложенных полей.
  3. Подмените контекст в тесте.

Вопросы с ответами

Связанные темы