Provide/inject для передачи данных

Механизм provide/inject в Vue.js предназначен для передачи данных от родительского компонента к потомкам на любом уровне вложенности, минуя цепочку props. Он позволяет создавать зависимости, которые будут доступны всем потомкам, не требуя явной передачи через каждый уровень компонентов.


Определение и синтаксис

В родительском компоненте используется свойство provide, которое может быть объектом или функцией:

export default {
  provide() {
    return {
      user: this.user,
      theme: 'dark'
    };
  },
  data() {
    return {
      user: { name: 'Иван', age: 30 }
    };
  }
}

Ключевые моменты:

  • Если provide — функция, она получает контекст компонента (this), что позволяет предоставлять реактивные данные.
  • Если provide — объект, данные являются статическими и не реактивными.

Использование Inject в дочерних компонентах

Дочерний компонент получает данные с помощью свойства inject:

export default {
  inject: ['user', 'theme'],
  mounted() {
    console.log(this.user.name); // 'Иван'
    console.log(this.theme);     // 'dark'
  }
}

Особенности:

  • inject может быть массивом строк (имена ключей) или объектом, где ключи задают локальные имена, а значения — имена из provide.
  • Можно задать значения по умолчанию, если родитель не предоставляет зависимость:
inject: {
  locale: {
    from: 'locale',
    default: 'ru-RU'
  }
}

Реактивность Provide/Inject

По умолчанию простые объекты, переданные через provide, не являются реактивными. Для реактивности следует использовать reactive или ref:

import { reactive, ref, provide } from 'vue';

export default {
  setup() {
    const user = reactive({ name: 'Иван', age: 30 });
    const theme = ref('dark');

    provide('user', user);
    provide('theme', theme);

    return {};
  }
}

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

import { inject } from 'vue';

export default {
  setup() {
    const user = inject('user');
    const theme = inject('theme');

    function changeName() {
      user.name = 'Пётр';
      theme.value = 'light';
    }

    return { user, theme, changeName };
  }
}

Вложенные Provide/Inject

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

// Родитель
provide('config', { apiUrl: '/api' });

// Глубокий потомок
inject('config'); // доступ к { apiUrl: '/api' }

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


Практические сценарии применения

  1. Глобальные настройки Передача темы, локали, API-конфигураций, токенов авторизации.

  2. Менеджеры состояния модулей Использование provide/inject для предоставления контекста состояния без подключения Vuex или Pinia.

  3. Повторно используемые компоненты Компоненты библиотеки могут получать конфигурации через inject, не завися от конкретного родителя.


Отличия от Props и Vuex

Механизм Передача данных Глубина Реактивность по умолчанию
Props Родитель → ребёнок 1 уровень Да
Provide/Inject Родитель → потомки Любая Нет (только через reactive/ref)
Vuex/Pinia Глобально Любая Да

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


Рекомендации по использованию

  • Обеспечивать реактивность через ref или reactive, если данные будут меняться.
  • Использовать объектную форму inject для указания значений по умолчанию.
  • Ограничивать область использования provide/inject небольшими, независимыми модулями, чтобы избежать сложного отслеживания зависимостей.
  • Помнить, что изменения в предоставленном объекте влияют на все потомки, что делает provide/inject удобным для shared state внутри локальных модулей.

Механизм provide/inject в Vue.js является гибким инструментом для передачи данных через иерархию компонентов, обеспечивая лёгкость доступа к зависимостям и упрощая управление контекстом приложения без необходимости передачи данных через каждый уровень компонентов.