Управление состоянием во Vue 3: provide/inject и Pinia

Vue 3 предлагает гибкие инструменты для обмена данными между компонентами.
Если props и emits позволяют взаимодействовать между родителем и ребёнком, то provide и inject дают возможность передавать данные через несколько уровней вложенности, а Pinia обеспечивает централизованное и удобное хранение состояния во всём приложении.

🧩 1. Что такое provide и inject

В больших приложениях данные часто нужно передавать вглубь дерева компонентов, минуя промежуточные уровни.
Чтобы не прокидывать props вручную через каждый уровень, Vue 3 предлагает механизм provide и inject.

  • provide — «предоставляет» значение.

  • inject — «получает» это значение в любом дочернем компоненте.

Пример:

<!-- App.vue -->
<template>
  <h1>Главный компонент</h1>
  <ChildComponent />
</template>

<script setup>
import { ref, provide } from 'vue'
import ChildComponent from './ChildComponent.vue'

const theme = ref('dark')
provide('theme', theme)
</script>
<!-- ChildComponent.vue -->
<template>
  <p>Текущая тема: {{ theme }}</p>
</template>

<script setup>
import { inject } from 'vue'

const theme = inject('theme')
</script>

Теперь компонент ChildComponent имеет доступ к значению theme, даже если между ним и App.vue есть другие уровни вложенности.

⚙️ 2. Реактивность с provide/inject

Если ты передаёшь реактивные значения (ref или reactive), то изменения автоматически обновятся во всех компонентах, которые их используют.

<!-- App.vue -->
<template>
  <button @click="toggleTheme">Переключить тему</button>
  <ChildComponent />
</template>

<script setup>
import { ref, provide } from 'vue'
import ChildComponent from './ChildComponent.vue'

const theme = ref('dark')
function toggleTheme() {
  theme.value = theme.value === 'dark' ? 'light' : 'dark'
}

provide('theme', theme)
</script>

Теперь при изменении theme интерфейс всех дочерних компонентов обновится автоматически.
Это и есть сила реактивности Vue 3.

🧠 3. Когда использовать provide/inject

✅ Подходит для:

  • тем оформления (dark/light);

  • локализации (i18n);

  • настроек форм;

  • зависимостей и сервисов (например, конфиг API).

⚠️ Не подходит для:

  • хранения общего состояния приложения (например, корзина, пользователь, настройки профиля).
    В таких случаях лучше использовать Pinia — современный менеджер состояния.

🧬 4. Pinia — современный state manager для Vue 3

Pinia — это официальная библиотека управления состоянием для Vue 3, пришедшая на смену Vuex.
Она проста, основана на Composition API и поддерживает TypeScript «из коробки».

Pinia позволяет хранить данные централизованно и использовать их в любых компонентах без цепочек props и emit.

⚙️ 5. Установка и настройка Pinia

Установим Pinia:

npm install pinia

Подключим её в main.js:

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
app.use(createPinia())
app.mount('#app')

🧩 6. Создание хранилища (store)

Хранилище — это как мини-база данных твоего приложения.

// stores/useCounterStore.js
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
  // состояние
  const count = ref(0)

  // геттер (computed)
  const double = computed(() => count.value * 2)

  // действия
  function increment() {
    count.value++
  }

  // возвращаем всё, что хотим использовать снаружи
  return { count, double, increment }
})

💻 7. Использование Pinia в компоненте

<template>
  <h2>Счётчик: {{ counter.count }}</h2>
  <p>Удвоенное значение: {{ counter.double }}</p>
  <button @click="counter.increment">+</button>
</template>

<script setup>
import { useCounterStore } from '@/stores/useCounterStore'

const counter = useCounterStore()
</script>

Хранилище counter теперь доступно во всём приложении.
Можно вызывать методы, изменять состояние и использовать геттеры — всё реактивно и удобно.

💡 Заключение

provide и inject — отличное решение для локального обмена данными между компонентами.
Pinia — мощный инструмент для глобального управления состоянием во Vue 3.

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