Provide/inject у Vue.js
Що таке provide/inject?
provide та inject — це пара API для передачі даних від батьківського компонент до будь-якого нащадка без явної передачі через пропси на кожному рівні.
Це вирішує проблему "пробивання пропсів" — коли потрібно передавати пропси через багато компонентів.
Основне використання
Composition API
<!-- App.vue (батьківський) -->
<template>
<ChildComponent />
</template>
<script setup>
import { provide, ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const theme = ref('dark')
provide('theme', theme)
</script><!-- GrandchildComponent.vue (нащадок) -->
<template>
<div :class="theme">
Тема: {{ theme }}
</div>
</template>
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
</script>Реактивність
Передача реактивних даних
<!-- App.vue -->
<template>
<button @click="theme = theme === 'dark' ? 'light' : 'dark'">
Перемкнути тему
</button>
<ChildComponent />
</template>
<script setup>
import { provide, ref } from 'vue'
const theme = ref('dark')
// Передайте ref, а не значення
provide('theme', theme)
</script><!-- DeepChild.vue -->
<template>
<div :class="theme">
Поточна тема: {{ theme }}
</div>
</template>
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
// тема автоматично оновиться при зміні
</script>Передача функцій для модифікації
<!-- App.vue -->
<script setup>
import { provide, ref } from 'vue'
const count = ref(0)
const increment = () => {
count.value++
}
provide('count', count)
provide('increment', increment)
</script><!-- DeepChild.vue -->
<template>
<p>Кількість: {{ count }}</p>
<button @click="increment">Збільшити</button>
</template>
<script setup>
import { inject } from 'vue'
const count = inject('count')
const increment = inject('increment')
</script>Значення за замовчуванням
<script setup>
import { inject } from 'vue'
// Якщо 'theme' не надано, використовуйте 'light'
const theme = inject('theme', 'light')
// Значення за замовчуванням як функція
const user = inject('user', () => ({ name: 'Гість' }))
// Третій параметр - значення обчислюється як фабрика
const config = inject('config', () => {
return { /* складна логіка */ }
}, true)
</script>Символьні ключі
Використання Symbol запобігає конфліктам імен:
// keys.js
export const ThemeKey = Symbol('theme')
export const UserKey = Symbol('user')<!-- App.vue -->
<script setup>
import { provide, ref } from 'vue'
import { ThemeKey, UserKey } from './keys'
const theme = ref('dark')
const user = ref({ name: 'John' })
provide(ThemeKey, theme)
provide(UserKey, user)
</script><!-- Child.vue -->
<script setup>
import { inject } from 'vue'
import { ThemeKey, UserKey } from './keys'
const theme = inject(ThemeKey)
const user = inject(UserKey)
</script>provide/inject на рівні застосунку
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.provide('apiUrl', 'https://api.example.com')
app.provide('appName', 'Мій додаток')
app.mount('#app')<!-- AnyComponent.vue -->
<script setup>
import { inject } from 'vue'
const apiUrl = inject('apiUrl')
const appName = inject('appName')
console.log(apiUrl) // 'https://api.example.com'
console.log(appName) // 'Мій додаток'
</script>provide/inject проти пропсів
Коли використовувати пропси
<!-- Прямий батьківсько-дитячий зв'язок -->
<ChildComponent :title="title" :count="count" />Використовуйте пропси, коли:
- Компоненти безпосередньо пов'язані
- Потрібен явний зв'язок даних
- Проста ієрархія (1-2 рівні)
Коли використовувати provide/inject
<!-- Глибока ієрархія -->
<GrandParent>
<Parent>
<Child>
<DeepChild /> <!-- Потрібні дані з GrandParent -->
</Child>
</Parent>
</GrandParent>Використовуйте provide/inject, коли:
- Глибока ієрархія компонентів
- Багато проміжних компонентів
- Глобальний контекст (тема, локаль, API)
Загальні помилки
Передача не реактивного значення
<!-- Неправильно -->
<script setup>
import { provide, ref } from 'vue'
const count = ref(0)
provide('count', count.value) // Передає лише значення, а не ref!
</script>
<!-- Правильно -->
<script setup>
import { provide, ref } from 'vue'
const count = ref(0)
provide('count', count) // Передає ref
</script>Мутація даних у дочірньому компоненті
<!-- Неправильно -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
// Не рекомендується змінювати безпосередньо
theme.value = 'dark'
</script>
<!-- Правильно - передайте функцію для модифікації -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
const setTheme = inject('setTheme')
setTheme('dark')
</script>Висновок
provide/inject:
- Передає дані через ієрархію без пропсів
- Вирішує проблему пробивання пропсів
- Підтримує реактивність
- Може використовувати Symbol для ключів
- Підходить для глобального стану (тема, локаль)
- Не замінює Vuex/Pinia для складного управління станом
На співбесідах:
Важливо вміти:
- Пояснити, що таке provide/inject і чому це потрібно
- Описати проблему пробивання пропсів
- Показати, як працює реактивність з provide/inject
- Пояснити різницю між provide/inject та пропсами
- Навести приклади використання (тема, API клієнт)
Зміст
Що таке provide/inject?Основне використанняComposition APIРеактивністьПередача реактивних данихПередача функцій для модифікаціїЗначення за замовчуваннямСимвольні ключіprovide/inject на рівні застосункуprovide/inject проти пропсівКоли використовувати пропсиКоли використовувати provide/injectЗагальні помилкиПередача не реактивного значенняМутація даних у дочірньому компонентіВисновок
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.