Provide / Inject
Tato stránka předpokládá, že už jste četli Základy komponent. Pokud jsou pro vás komponenty nové, přečtěte si je jako první.
Drilling vlastností
Pokud potřebujeme předat data z nadřazené komponenty podřazené komponentě, použijeme obvykle vlastnosti (props). Představte si však případ, kdy máme rozsáhlý strom komponent a hluboko vnořená komponenta potřebuje něco ze komponenty vzdáleného předka. Pokud bychom používali pouze vlastnosti, museli bychom předávat stejnou vlastnost napříč celým řetězcem rodičů:
Všimněte si, že ačkoli komponentu <Footer>
tyto vlastnosti možná vůbec nezajímají, musí je deklarovat a předat dál, aby k nim komponenta <DeepChild>
měla přístup. Pokud by existoval delší rodičovský řetězec, ovlivnilo by to po cestě ještě více komponent. Tomu se říká „props drilling“ a rozhodně není zábavné se s tím potýkat.
Drilling vlastností můžeme řešit pomocí provide
a inject
. Komponenta rodiče může sloužit jako poskytovatel závislostí (dependency provider) pro všechny své potomky. Jakákoli komponenta ve stromu potomků, bezohledu na hloubku jejího zanoření, může implementovat (inject) závislosti poskytované komponentami v rodčovském řetězci.
Provide
Pro poskytnutí dat komponentám potomků použijte funkci provide()
:
vue
<script setup>
import { provide } from 'vue'
provide(/* klíč */ 'message', /* hodnota */ 'Ahoj!')
</script>
Pokud nepoužíváte <script setup>
, ujistetě se, že je provide()
voláno synchronně uvnitř setup()
funkce:
js
import { provide } from 'vue'
export default {
setup() {
provide(/* klíč */ 'message', /* hodnota */ 'Ahoj!')
}
}
Funkce provide()
přijímá dva parametry. První parametr se nazývá injection key, což může být string nebo Symbol
. Injection key je použit v komponentně potomka k vyhledání hodnoty, která má být implementována. Jedna komponenta může volat provide()
vícekrát s různými injection keys pro poskytnutí různých hodnot.
Druhý parametr je poskytovaná hodnota. Hodnota může být jakéhokoli typu vč. reaktivního stavu jako jsou refs:
js
import { ref, provide } from 'vue'
const count = ref(0)
provide('key', count)
Poskytnutí reaktivních hodnot umožňuje komponentám potomků, které poskytnutou hodnotu používají, navázat reaktivní spojení s komponentou zprostředkovatele.
Provide na úrovni aplikace
Kromě poskytování dat v komponentě můžeme data poskytovat také na úrovni celé aplikace:
js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* klíč */ 'message', /* hodnota */ 'Ahoj!')
Provide na úrovni aplikace je k dispozici všem komponentám vykresleným v aplikaci. Zvlášť užitečné je to při psaní pluginů, protože pluginy obvykle nejsou schopny poskytovat hodnoty pomocí komponent.
Inject
Pro implementaci dat poskytnutých komponentou předka použijte funkci inject()
:
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
Pokud je poskytovaná hodnota ref, bude jako ref implementována a nebude automaticky rozbalena. To umožňuje komponentě, která implementuje, zachovat reaktivitu spojení s komponentou, která data poskytuje.
Kompletní provide/inject příklad vč. reaktivity
Opět, pokud nepoužíváte <script setup>
, inject()
lze volat pouze synchronně uvnitř setup()
:
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}
Výchozí hodnoty pro implementaci
Ve výchozím nastavení inject
předpokládá, že implementovaná hodnota je někde v rodičovském řetězci poskytována. V případě, že klíč poskytnut není, zobrazí se runtime varování.
Pokud chceme, aby implementovaná vlastnost fungovala s volitelnými poskytovateli, musíme deklarovat výchozí hodnotu, podobně jako u vlastností:
js
// pokud není poskytnuta žáná odpovídající "message"
// `value` bude "default value"
const value = inject('message', 'default value')
V některých případech může být nutné výchozí hodnotu vytvořit voláním funkce nebo instancí nové třídy. Abychom se vyhnuli zbytečným výpočtům nebo vedlejším efektům v případě, že volitelnou hodnotu nepoužijeme, můžeme pro vytvoření výchozí hodnoty použít tovární (factory) metodu:
js
const value = inject('key', () => new ExpensiveClass(), true)
Třetí parametr indikuje, že výchozí hodnota by měla být považována za tovární funkci.
Práce s reaktivitou
Když používáme reaktivní provide/inject hodnoty, je doporučeno provádět všechny změny reaktivního stavu uvnitř provider komponenty, kdykoli je to možné. Tím je zajištěno, že jsou poskytnutý stav a jeho případné změny umístěny ve stejné komponentě, což usnadňuje budoucí údržbu.
V některých případech můžeme potřebovat aktualizovat data z komponenty, která poskytnutá data implementuje. V takových případech doporučujeme poskytovat funkci, která je za změny stavu zodpovědná:
vue
<!-- uvnitř komponenty, která poskytuje -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('Severní pól')
function updateLocation() {
location.value = 'Jižní pól'
}
provide('location', {
location,
updateLocation
})
</script>
vue
<!-- uvnitř komponenty, která implementuje -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>
Pokud se chcete ujistit, že data předaná skrz provide
nemohou být změněna komponentou, která je implementuje, můžte poskytovanou hodnotu obalit pomocí readonly()
.
vue
<script setup>
import { ref, provide, readonly } from 'vue'
const count = ref(0)
provide('read-only-count', readonly(count))
</script>
Práce s klíči typu Symbol
Dosud jsme v příkladech používali injection kyes typu string. Pokud pracujete v rozsáhlé aplikaci s mnoha poskytovateli závislostí nebo vytváříte komponenty, které budou používat i další vývojáři, je nejlepší používat injection kyes typu Symbol, abyste se vyhnuli případným kolizím.
Je doporučeno exportovat použité symboly do vyhrazeného souboru:
js
// keys.js
export const myInjectionKey = Symbol()
js
// uvnitř komponenty, která poskytuje
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, {
/* poskytovaná data */
})
js
// uvnitř komponenty, která implementuje
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)
Viz také: Typování Provide / Inject