Механизм Provide Inject - как он работает и когда применять

28 января 2026
Автор

Олег Марков

Введение

Механизм Provide/Inject (часто пишут provide/inject или provide-inject) встречается в разных фреймворках и языках программирования, но его суть почти всегда одна и та же. У вас есть некий "поставщик" значения (provide), который делает данные или объекты доступными "глубоко" в иерархии, и есть "потребители" (inject), которые эти данные получают, минуя длинные цепочки параметров и пропсов.

Чаще всего вы сталкиваетесь с Provide/Inject в следующих ситуациях:

  • во фронтенде
    • Vue 3 (композиционное API и опции компонентов)
    • Nuxt
    • иногда в обвязках вокруг React или других библиотек
  • в backend и DI-контейнерах
    • Angular (NgModule providers)
    • NestJS
    • разные IoC/DI контейнеры в Go, Java, C#

В этой статье я буду объяснять концепцию на примерах Vue 3, потому что там Provide/Inject особенно нагляден и прост. Но вам будет полезно и в других стекх: идея и типичные ошибки везде одинаковые.

Давайте разберем, как Provide/Inject работает, когда он нужен, какие у него ограничения и как не попасть в типичные ловушки.

Базовая идея Provide/Inject

Зачем вообще нужен Provide/Inject

Представьте дерево компонентов:

  • Корневой компонент App
    • Компонент Layout
      • Компонент Sidebar
        • Компонент Menu
          • Компонент MenuItem

Если вам нужно передать одно и то же значение (например, текущего пользователя, настройки темы или инстанс какого-то сервиса) от App до MenuItem, у вас есть несколько вариантов:

  1. Прокидывать пропсы через каждый уровень

    • App -> Layout -> Sidebar -> Menu -> MenuItem
    • каждый промежуточный компонент обязан знать о значении и передавать его дальше
  2. Использовать глобальное хранилище

    • Vuex, Pinia, Redux и т.д.
    • по сути, "глобальная" точка доступа
  3. Использовать Provide/Inject

    • App делает provide значения
    • MenuItem делает inject и сразу получает нужные данные
    • промежуточные компоненты ничего о значении не знают

Provide/Inject хорошо подходит, когда:

  • значение логически "принадлежит" какому-то родительскому компоненту
  • это значение нужно только части поддерева
  • вы не хотите "засорять" пропсами все промежуточные уровни
  • вы хотите сохранить компонент переиспользуемым (чтобы он не имел кучи "лишних" пропсов только ради проброса)

Как устроена пара Provide / Inject в общем виде

На концептуальном уровне:

  • provide(key, value) — регистрирует значение в текущем "контейнере" (компоненте, модуле, контексте)
  • inject(key) — ищет значение с этим ключом в ближайшем родителе, затем выше по дереву, пока не найдет

То есть это поиск "вверх" по иерархии, а не "вниз". Компонент, который делает inject, не знает и не должен знать, кто именно сделал provide этого значения. Его волнует только ключ и контракт (тип/структура значения).

Иногда механизм поддерживает:

  • дефолтное значение, если ничего не найдено
  • ленивую инициализацию (дефолт как функция)
  • реактивность (если используется в реактивных фреймворках)
  • строгую типизацию при использовании TypeScript

Давайте теперь посмотрим на конкретную реализацию на примере Vue 3.

Provide/Inject в Vue 3 – базовый пример

Простейший пример с Options API

Сначала посмотрим на классический синтаксис Vue с опцией provide/inject. Здесь я показываю максимально простой пример, чтобы вы увидели общую идею.

Родительский компонент

// App.vue
export default {
  name: 'App',

  // provide как объект или функция
  provide() {
    return {
      // Ключ 'theme' и значение 'dark'
      // Это значение смогут получить дочерние компоненты с помощью inject
      theme: 'dark'
    }
  }
}

Дочерний компонент

// Child.vue
export default {
  name: 'Child',

  // inject - перечисляем ключи, которые хотим получить
  inject: ['theme'],

  mounted() {
    // Здесь this.theme содержит значение, предоставленное родителем
    console.log('Текущая тема:', this.theme) // Текущая тема: dark
  }
}

Здесь:

  • App делает provide ключа theme
  • Child делает inject того же ключа theme
  • промежуточные компоненты не обязаны ничего знать о теме

Важно: связь осуществляется только по имени ключа. Если вы опечатаетесь в ключе, Vue просто не найдет значение.

Provide/Inject с Composition API

На практике сегодня чаще используют Composition API: функции setup, provide и inject из пакета vue.

Давайте разберем тот же пример, но уже с Composition API.

Родительский компонент с provide

// App.vue
import { defineComponent, provide } from 'vue'

export default defineComponent({
  name: 'App',

  setup() {
    // Здесь мы "предоставляем" значение под ключом 'theme'
    provide('theme', 'dark')

    // Можно предоставлять и сложные объекты, а не только строки
    const user = {
      id: 1,
      name: 'Alex'
    }

    // Здесь мы предоставляем объект user под ключом 'currentUser'
    provide('currentUser', user)

    // Компонент по-прежнему может что-то возвращать в шаблон
    return {}
  }
})

Дочерний компонент с inject

// Child.vue
import { defineComponent, inject } from 'vue'

export default defineComponent({
  name: 'Child',

  setup() {
    // Получаем значение по ключу 'theme'
    const theme = inject('theme')

    // Получаем объект пользователя по ключу 'currentUser'
    const currentUser = inject('currentUser')

    // В шаблон можно вернуть что-то производное или сами значения
    return {
      theme,
      currentUser
    }
  }
})

Смотрите, я не завязываю Child на App напрямую. Мне важно только, чтобы в каком-то родителе по дереву был вызван provide с тем же ключом.

Ключи provide/inject – строки, символы и константы

Почему лучше не использовать "магические строки"

Если вы пишете:

provide('theme', 'dark')
const theme = inject('theme')

то между этими строками нет явной связи на уровне типов и автодополнения. Опечатка в одной из строк не будет найдена до рантайма.

Поэтому хороший подход — выносить ключи в константы или использовать Symbol.

Вариант 1 – константа-строка

// keys.js
export const THEME_KEY = 'theme'
// App.vue
import { defineComponent, provide } from 'vue'
import { THEME_KEY } from './keys'

export default defineComponent({
  setup() {
    provide(THEME_KEY, 'dark')
  }
})
// Child.vue
import { defineComponent, inject } from 'vue'
import { THEME_KEY } from './keys'

export default defineComponent({
  setup() {
    const theme = inject(THEME_KEY) // меньше шансов ошибиться в названии
    return { theme }
  }
})

Вариант 2 – Symbol как ключ

Symbol часто используют, чтобы гарантировать уникальность ключа и избежать конфликтов имен.

// keys.js
export const ThemeKey = Symbol('theme')
// App.vue
import { defineComponent, provide } from 'vue'
import { ThemeKey } from './keys'

export default defineComponent({
  setup() {
    // Здесь ключом служит Symbol, а не строка
    provide(ThemeKey, 'dark')
  }
})
// Child.vue
import { defineComponent, inject } from 'vue'
import { ThemeKey } from './keys'

export default defineComponent({
  setup() {
    // Ключ ThemeKey тот же самый Symbol, поэтому inject найдет значение
    const theme = inject(ThemeKey)
    return { theme }
  }
})

В TypeScript это особенно удобно, потому что можно привязать типы к этому символу.

Реактивность при использовании Provide/Inject

Важный момент – provide не делает значение реактивным сам по себе

Если вы просто передадите примитив:

provide('theme', 'dark')

и потом попытаетесь поменять его значение где-то в родителе, это не обновит значение в дочерних компонентах. Почему так происходит:

  • Vue не "оборачивает" значение в реактивный контейнер автоматически
  • вы передали обычную строку, а не реактивную ссылку или объект

Чтобы сделать значение реактивным, нужно передавать ref или reactive.

Пример с ref

// App.vue
import { defineComponent, provide, ref } from 'vue'

export default defineComponent({
  name: 'App',

  setup() {
    // Создаем реактивную ссылку на тему
    const theme = ref('dark')

    // Предоставляем именно ref, а не голое значение
    provide('theme', theme)

    // Где-то в родителе мы можем менять theme.value
    // и дочерние компоненты увидят изменения
    function toggleTheme() {
      // Здесь мы переключаем тему
      theme.value = theme.value === 'dark' ? 'light' : 'dark'
    }

    return {
      theme,
      toggleTheme
    }
  }
})
// Child.vue
import { defineComponent, inject } from 'vue'

export default defineComponent({
  name: 'Child',

  setup() {
    // Получаем ref
    const theme = inject('theme')

    // Обратите внимание - для работы с ref в шаблоне
    // Vue автоматически разыменует .value
    return {
      theme
    }
  }
})

В этом примере:

  • родитель хранит состояние темы как ref
  • provide делится этим ref с потомками
  • потомки реагируют на изменения, потому что работают с тем же ref

Пример с reactive объектом

Если вы предоставите целый объект состояния, его тоже лучше сделать реактивным.

// App.vue
import { defineComponent, provide, reactive } from 'vue'

export default defineComponent({
  name: 'App',

  setup() {
    // Создаем реактивный объект настроек
    const settings = reactive({
      theme: 'dark',
      language: 'en'
    })

    // Предоставляем объект
    provide('settings', settings)

    // Любые изменения settings.theme или settings.language
    // будут автоматически видны в потомках
    return {
      settings
    }
  }
})
// Child.vue
import { defineComponent, inject } from 'vue'

export default defineComponent({
  name: 'Child',

  setup() {
    // Получаем тот же самый reactive объект
    const settings = inject('settings')

    // Теперь вы можете читать и изменять settings.theme, settings.language
    // и эти изменения будут реактивными
    return {
      settings
    }
  }
})

Выбирайте ref или reactive в зависимости от структуры данных:

  • ref — если это одно значение
  • reactive — если это объект или сложная структура

Provide/Inject и TypeScript

Типизация inject

По умолчанию функция inject в Vue 3 имеет тип:

  • возвращает значение типа unknown

То есть без подсказки типов вы получаете значение, которым неудобно пользоваться в TypeScript.

Чтобы задать тип, есть два подхода.

Подход 1 – дженерик у inject

import { defineComponent, provide, inject, ref, Ref } from 'vue'

const ThemeKey = Symbol('theme')

export default defineComponent({
  setup() {
    const theme = ref<'dark' | 'light'>('dark')
    provide(ThemeKey, theme)

    return {}
  }
})

// В другом файле
export const Child = defineComponent({
  setup() {
    // Указываем тип явно
    const theme = inject<Ref<'dark' | 'light'>>(ThemeKey)

    if (!theme) {
      // Здесь можно обработать ситуацию, если значение не найдено
      throw new Error('Theme is not provided')
    }

    // Теперь theme имеет тип Ref<'dark' | 'light'>
    return { theme }
  }
})

Комментарии к этому коду:

  • дженерик <Ref<'dark' | 'light'>> говорит TypeScript, чего мы ожидаем
  • inject может вернуть undefined, поэтому нужно учитывать этот случай
  • часто в таких местах вы либо кидаете ошибку, либо задаете дефолт

Подход 2 – дефолтное значение и тип по нему

import { defineComponent, inject, ref, Ref } from 'vue'

const ThemeKey = Symbol('theme')

export const Child = defineComponent({
  setup() {
    // Передаем дефолт, чтобы inject всегда возвращал значение
    const defaultTheme = ref<'dark' | 'light'>('light')

    const theme = inject<Ref<'dark' | 'light'>>(ThemeKey, defaultTheme)

    // Здесь theme гарантированно не undefined
    return { theme }
  }
})

Дефолтное значение:

  • используется, если никакой provide по этому ключу не найден
  • позволяет не писать дополнительные проверки на undefined

Типизация ключей

Если вы используете Symbol как ключ, вы можете описать key более строго:

import type { InjectionKey, Ref } from 'vue'

// Описываем ключ с указанием типа значения, которое будет предоставлено
export const ThemeKey: InjectionKey<Ref<'dark' | 'light'>> = Symbol('theme')

Теперь:

  • при provide(ThemeKey, value) TypeScript проверит, что value соответствует типу Ref<'dark' | 'light'>
  • при inject(ThemeKey) TypeScript поймет, что вы получаете Ref<'dark' | 'light'> | undefined

Это очень удобно для больших проектов.

Наследование и переопределение provide

Как работает поиск значения при inject

Когда компонент вызывает inject:

  1. Vue смотрит на ближайшего родителя
  2. если у родителя есть provide с нужным ключом — берет его
  3. если нет — поднимается выше и повторяет поиск
  4. если никто не предоставил — возвращает undefined или дефолт, если он задан

Таким образом, дерево компонентов работает, как цепочка областей видимости.

Переопределение значения ниже по дереву

Компонент-потомок может сам сделать provide с тем же ключом, и его дети будут видеть уже новое значение.

Давайте разберем на примере.

// Root.vue
import { defineComponent, provide } from 'vue'

export default defineComponent({
  name: 'Root',
  setup() {
    // Предоставим значение level = 1
    provide('level', 1)
  }
})
// ChildA.vue
import { defineComponent, inject, provide } from 'vue'

export default defineComponent({
  name: 'ChildA',
  setup() {
    // Получаем значение от родителя
    const parentLevel = inject('level', 0)

    // Вычисляем новый уровень для себя
    const myLevel = parentLevel + 1

    // Предоставляем свой уровень дальше вниз по дереву
    provide('level', myLevel)

    return {
      myLevel
    }
  }
})
// ChildB.vue
import { defineComponent, inject } from 'vue'

export default defineComponent({
  name: 'ChildB',
  setup() {
    // Здесь мы получаем уже переопределенное значение
    const level = inject('level', 0)

    return {
      level
    }
  }
})

В этом примере:

  • Root предоставляет level = 1
  • ChildA повышает уровень до 2 и предоставляет дальше
  • ChildB, будучи потомком ChildA, увидит уже level = 2

Такой прием удобно использовать, например, в компонентах, которые строят вложенные списки, деревья или формируют структуру по уровням (заголовки, элементы меню и т.д.).

Provide/Inject vs Props vs Store – когда что использовать

Очень часто возникает вопрос: когда стоит использовать Provide/Inject, а когда лучше обойтись пропсами или глобальным стором?

Давайте разберем.

Когда лучше использовать пропсы

Используйте пропсы, когда:

  • значение нужно передать только на 1–2 уровня вниз
  • связь родитель–ребенок прозрачна и логична
  • важно, чтобы интерфейс компонента был явно описан (пропсы как "публичный API")

Пропсы дают:

  • хорошую читаемость — открываете компонент, видите, какие у него входные данные
  • простую типизацию
  • предсказуемое поведение

Когда уместен Provide/Inject

Используйте Provide/Inject, когда:

  • значение нужно передавать на глубину 3+ уровней
  • много промежуточных компонентов, которые не используют значение напрямую
  • вы не хотите "засорять" пропсами интерфейс компонентов, которые реальное значение не используют
  • значение логически относится ко всему поддереву — например:
    • форма и все ее поля
    • таблица и ячейки
    • контекст авторизации для целого раздела

Типичные задачи:

  • тема (theme) в рамках модуля
  • текущий пользователь или контекст доступа в конкретной части приложения
  • конфигурация формы или таблицы
  • общий сервис для набора вложенных компонентов

Когда нужен глобальный store (Vuex/Pinia и аналоги)

Глобальный store предпочтителен, если:

  • значение должно быть доступно из разных веток дерева, а не только по одной иерархии
  • это "глобальное состояние" всего приложения
  • вам нужны инструменты вроде time-travel дебаггера, логирования, сериализации состояния

Простейшее правило:

  • локальная задача в одном поддереве — Provide/Inject
  • короткая цепочка родитель–ребенок — пропсы/эмиты
  • глобальное состояние всего приложения — store

Примеры реальных сценариев использования Provide/Inject

Пример 1 – общая конфигурация формы и полей

Давайте разберем довольно типичную задачу: у вас есть компонент Form, в нем несколько InputField и SelectField. Вы хотите:

  • задать общую тему и размер полей
  • хранить общее состояние в Form
  • не передавать кучу пропсов каждому полю

Родитель Form

// Form.vue
import { defineComponent, provide, reactive } from 'vue'

const FormContextKey = Symbol('FormContext')

export default defineComponent({
  name: 'Form',

  props: {
    size: {
      type: String,
      default: 'md' // допустим 'sm', 'md', 'lg'
    },
    theme: {
      type: String,
      default: 'light' // light или dark
    }
  },

  setup(props) {
    // Создаем общий контекст формы
    const formContext = reactive({
      size: props.size,
      theme: props.theme,
      // Можно добавить методы для валидации, сабмита и т.д.
      // Для простоты оставим только конфигурацию
    })

    // Предоставляем контекст всем потомкам формы
    provide(FormContextKey, formContext)

    return {
      formContext
    }
  }
})

Поле ввода InputField

// InputField.vue
import { defineComponent, inject } from 'vue'
import { FormContextKey } from './keys'

export default defineComponent({
  name: 'InputField',

  props: {
    modelValue: String,
    label: String
  },

  emits: ['update:modelValue'],

  setup(props, { emit }) {
    // Получаем контекст формы
    const formContext = inject(FormContextKey)

    // Здесь formContext может быть undefined,
    // если InputField используют вне Form
    // поэтому имеет смысл задать дефолты
    const size = formContext?.size || 'md'
    const theme = formContext?.theme || 'light'

    function onInput(event) {
      // Пробрасываем новое значение наверх через v-model
      emit('update:modelValue', event.target.value)
    }

    return {
      size,
      theme,
      onInput
    }
  }
})

Теперь вы можете использовать такую связку в шаблоне:

<Form size="lg" theme="dark">
  <InputField v-model="user.name" label="Имя" />
  <InputField v-model="user.email" label="Email" />
</Form>

Как видите, каждый InputField автоматически подхватывает размер и тему от Form, при этом сам компонент InputField остается довольно чистым — он не принимает отдельные пропсы size и theme в явном виде (или принимает, но имеет дефолты из контекста).

Пример 2 – дерево меню с уровнями вложенности

Сейчас покажу вам пример, в котором используется идея "уровней" из более раннего раздела.

Компонент Menu

// Menu.vue
import { defineComponent, provide } from 'vue'

const LevelKey = Symbol('Level')

export default defineComponent({
  name: 'Menu',

  setup() {
    // Корневой уровень меню = 1
    provide(LevelKey, 1)

    return {}
  }
})

Компонент MenuGroup (вложенная группа)

// MenuGroup.vue
import { defineComponent, inject, provide } from 'vue'
import { LevelKey } from './keys'

export default defineComponent({
  name: 'MenuGroup',

  setup() {
    // Получаем уровень от родителя
    const parentLevel = inject(LevelKey, 0)
    const myLevel = parentLevel + 1

    // Предоставляем новый уровень дальше
    provide(LevelKey, myLevel)

    return {
      myLevel
    }
  }
})

Компонент MenuItem

// MenuItem.vue
import { defineComponent, inject } from 'vue'
import { LevelKey } from './keys'

export default defineComponent({
  name: 'MenuItem',

  props: {
    label: String
  },

  setup() {
    // Получаем текущий уровень элемента
    const level = inject(LevelKey, 1)

    return {
      level
    }
  }
})

Шаблон может выглядеть так:

<Menu>
  <MenuItem label="Главная" />
  <MenuGroup>
    <MenuItem label="Раздел 1" />
    <MenuItem label="Раздел 2" />
    <MenuGroup>
      <MenuItem label="Подраздел 2.1" />
    </MenuGroup>
  </MenuGroup>
</Menu>

Дальше вы можете использовать level внутри MenuItem, чтобы настроить:

  • отступы
  • размер шрифта
  • иконки для разных уровней

При этом вам не нужно явно передавать уровень в каждый компонент.

Частые ошибки и подводные камни Provide/Inject

Ошибка 1 – несоответствие ключей

Самая банальная, но очень частая ситуация — вы написали:

provide('theme', 'dark')
const theme = inject('them') // опечатка в ключе

Результат:

  • inject возвращает undefined
  • вы не сразу понимаете, почему значение "пропало"

Как избежать:

  • выносите ключи в константы или Symbol
  • используйте тип InjectionKey в TypeScript

Ошибка 2 – ожидание реактивности без ref/reactive

Вы делаете:

provide('count', 0)

и где-то в коде родителя:

// Изменяем локальную переменную count,
// но потомки не увидят изменений
count = 1

Причина: вы не передали ref или reactive, вы передали только первоначальное значение.

Как надо:

const count = ref(0)
provide('count', count)

// Теперь, изменяя count.value, вы обновляете значение и в потомках
count.value = 1

Ошибка 3 – использовать Provide/Inject вместо явных пропсов там, где это не нужно

Иногда разработчики начинают использовать Provide/Inject "везде", чтобы "не писать пропсы". В итоге:

  • становится сложно понять, откуда берется то или иное значение
  • компонент внешне выглядит "чистым", но на деле зависит от невидимых связей

Лучше придерживаться простого принципа:

  • если значение относится к самому компоненту и его API — используйте пропсы
  • если значение — общий контекст для поддерева — тогда Provide/Inject

Ошибка 4 – inject в компоненте, который может использоваться и вне контекста

Например, InputField из примера с формой можно использовать отдельно, без Form. Если вы жестко рассчитываете на контекст, компонент может упасть.

Как смягчить:

  • использовать inject с дефолтом
  • проверять наличие контекста и задавать разумные значения по умолчанию
const formContext = inject(FormContextKey, {
  size: 'md',
  theme: 'light'
})

Или:

const formContext = inject(FormContextKey, null)

const size = formContext?.size ?? 'md'
const theme = formContext?.theme ?? 'light'

Ошибка 5 – слишком "глобальный" контекст

Иногда через Provide/Inject пытаются "протянуть" практически все состояние приложения от корня. По сути это превращается в самодельный глобальный store, но:

  • без инструментов дебаггинга
  • без четкой структуры
  • с разрозненными ключами и контекстами

В таких случаях лучше рассмотреть:

  • Pinia / Vuex
  • или модульный store, а Provide/Inject использовать только для "локальных" контекстов

Краткое резюме

Механизм Provide/Inject позволяет:

  • передавать данные от родителя к потомкам на произвольную глубину
  • не прокидывать лишние пропсы через каждый уровень дерева
  • создавать локальные контексты для поддеревьев (формы, меню, таблицы и т.д.)
  • делиться реактивными значениями (ref/reactive) между компонентами

Ключевые моменты, которые важно запомнить:

  • всегда синхронизируйте ключи provide и inject, лучше через константы или Symbol
  • для реактивности передавайте ref или reactive
  • не подменяйте Provide/Inject там, где проще использовать обычные пропсы или глобальный store
  • переопределение provide ниже по дереву позволяет строить иерархические контексты (например, уровни вложенности)

Если вы будете следовать этим правилам, Provide/Inject станет удобным и предсказуемым инструментом, а не источником трудноуловимых багов.

Частозадаваемые технические вопросы по теме Provide/Inject

1. Как протестировать компоненты, которые используют inject, в unit-тестах?

В тестах вам нужно "подложить" значения, которые обычно приходят через provide. В Vue Test Utils можно использовать опцию global.provide.

Пример:

// Здесь мы монтируем компонент и подсовываем ему контекст через provide
const wrapper = mount(ChildComponent, {
  global: {
    provide: {
      theme: 'dark',
      currentUser: { id: 1, name: 'Test' }
    }
  }
})

Так вы контролируете значения, которые компонент получит через inject, и можете явно проверять поведение.

2. Можно ли вызывать provide динамически, уже после монтирования компонента?

Значения, которые вы передали в provide, могут меняться (если это ref или reactive), но сам вызов provide должен происходить внутри setup или в момент инициализации компонента. Добавлять новые ключи "задним числом" технически возможно, но это усложняет логику и может быть неочевидно. Обычно лучше заранее определить все ключи и передавать реактивные контейнеры, а не пытаться вызывать provide позже.

3. Как удалить или "отключить" значение, которое было предоставлено через provide?

Специального метода "unprovide" нет. Стандартный способ "отключить" значение — либо:

  • передать через provide значение null или другое "пустое" значение
  • ограничить время жизни компонента-поставщика (при его размонтировании контекст пропадет)

Если нужно условно предоставлять значение, вы можете управлять рендерингом компонента, который делает provide, через v-if.

4. Можно ли использовать provide/inject в логике вне компонентов, например, в отдельных модулях?

Нет, механизм привязан к контексту компонента и к его дереву. Вне компонента у Vue нет информации о текущем "иерархическом" контексте. Для логики вне компонентов (сервисы, утилиты) обычно используют:

  • импорт модулей напрямую
  • DI-контейнеры другого уровня
  • глобальные store или фабрики

5. Как быть, если один и тот же компонент нужно использовать с разными контекстами?

Вам нужно, чтобы компонент умел:

  • сначала смотреть в local provide/inject
  • затем, если контекста нет, использовать пропсы или локальные дефолты

Практически это выглядит так:

const context = inject(ContextKey, null)
// Если контекст есть — берем значения оттуда,
// иначе используем пропсы/дефолты
const size = context?.size ?? props.size ?? 'md'

Так компонент становится "гибридным" и может работать и внутри Provide/Inject-контекста, и отдельно.

Стрелочка влевоРеактивные переменные - концепция reactive и практические примерыPinia современный менеджер состояния для VueСтрелочка вправо

Постройте личный план изучения Vue до уровня Middle — бесплатно!

Vue — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Vuex - полное руководство по управлению состоянием во Vue приложенияхРеактивные ссылки ref - полный разбор для разработчиковРеактивные объекты reactive-objects - подробное руководство с примерамиРеактивные переменные - концепция reactive и практические примерыМеханизм Provide Inject - как он работает и когда применятьPinia современный менеджер состояния для VueЛокальное состояние local state в веб разработкеГлобальное состояние в приложениях - global state
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
Функция append в Go GolangОтображение компонента mounted - практическое руководствоХуки жизненного цикла компонентов - полное руководство для разработчиковУничтожение компонента destroyed - как правильно очищать ресурсы и подпискиИнициализация данных в состоянии created - как и когда подготавливать данные в приложенииОбновление компонента beforeUpdate во VueМонтирование компонента - хук beforeMount в VueРазрушение компонента во Vue - beforeDestroy и beforeUnmountСоздание экземпляра beforeCreate - полный разбор жизненного цикла
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Слоты компонента - концепция и практическое использованиеРегистрация компонентов component-registration в приложениях с внедрением зависимостейProps компонента в React - полный разбор с примерамиФункциональные компоненты в React - функциональный подход к построению интерфейсовСобытия компонента - events в современных интерфейсахДинамические компоненты - dynamic-componentsСоздание компонента component - практическое руководствоАсинхронные компоненты async-components - практическое руководство
Наблюдатели watchers - от паттерна до практических реализацийУправление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsШаблоны Vue templates - практическое руководство для разработчиковИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхСтруктура и особенности Single File Components SFC в VueПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueРеактивность Vue reactivity - как это работает под капотом и как этим пользоватьсяПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueОпции компонента в Go - паттерн component-optionsРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreВычисляемые свойства computed во Vue.jsСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueОсновы Vue - vue-basics для уверенного стартаИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueТелепортация - архитектура и реализация в серверных приложенияхРабота с teleport для управления DOM во VueSuspense в React - управление асинхронными данными и ленивой загрузкойПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиПлагины Vue vue-plugins - полное практическое руководствоРуководство по nextTick для работы с DOMМиксины - mixins в современном программированииJSX в Vue с использованием плагина vue-jsxСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьКастомные элементы - Custom Elements в современном JavaScriptИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Vue 3 и Pinia

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий