Provide / Inject (Dostarczanie / Wstrzykiwanie)
Ta strona zakłada, że przeczytałeś już Podstawy Komponentów. Przeczytaj je najpierw, jeśli dopiero zaczynasz pracę z komponentami.
Przekazywanie właściwości (Prop Drilling)
Zazwyczaj, gdy potrzebujemy przekazać dane z komponentu nadrzędnego do potomnego, używamy właściwości (props). Jednakże, wyobraź sobie przypadek, w którym mamy rozbudowane drzewo komponentów, a głęboko zagnieżdżony komponent potrzebuje czegoś od bardzo odległego komponentu przodka. Używając tylko właściwości (props), musielibyśmy przekazywać tę samą właściwość przez cały łańcuch komponentów nadrzędnych:
Zauważ, że chociaż komponent <Footer>
może w ogóle nie potrzebować tych właściwości, to nadal musi je zadeklarować i przekazać dalej, aby <DeepChild>
mógł uzyskać do nich dostęp. Jeśli łańcuch komponentów nadrzędnych jest dłuższy, więcej komponentów zostałoby dotkniętych po drodze. Jest to nazywane "props drilling" (przekazywaniem właściwości) i zdecydowanie nie jest przyjemne w obsłudze.
Możemy rozwiązać problem przekazywania właściwości za pomocą provide
i inject
. Komponent nadrzędny może służyć jako dostawca zależności dla wszystkich swoich potomków. Każdy komponent w drzewie potomnym, niezależnie od tego, jak głęboko się znajduje, może wstrzykiwać (inject) zależności dostarczone przez komponenty w jego łańcuchu nadrzędnym.
Provide (Dostarczanie)
Aby dostarczyć dane do komponentów potomnych, użyj funkcji provide()
:
vue
<script setup>
import { provide } from 'vue'
provide(/* klucz */ 'message', /* wartość */ 'hello!')
</script>
Jeśli nie używasz <script setup>
, upewnij się, że provide()
jest wywoływane synchronicznie wewnątrz setup()
:
js
import { provide } from 'vue'
export default {
setup() {
provide(/* klucz */ 'message', /* wartość */ 'hello!')
}
}
Funkcja provide()
przyjmuje dwa argumenty. Pierwszy argument nazywany jest kluczem wstrzykiwania i może być ciągiem znaków (string) lub Symbol
. Klucz wstrzykiwania jest używany przez komponenty potomne do wyszukiwania żądanej wartości do wstrzyknięcia. Pojedynczy komponent może wielokrotnie wywoływać provide()
z różnymi kluczami wstrzykiwania, aby dostarczyć różne wartości.
Drugim argumentem jest dostarczana wartość. Wartość może być dowolnego typu, włączając w to stan reaktywny, taki jak refs:
js
import { ref, provide } from 'vue'
const count = ref(0)
provide('key', count)
Dostarczanie wartości reaktywnych pozwala komponentom potomnym, które używają dostarczonej wartości, na ustanowienie reaktywnego połączenia z komponentem dostarczającym.
Dostarczanie na poziomie aplikacji (App-level Provide)
Oprócz dostarczania danych w komponencie możemy także dostarczać je na poziomie aplikacji:
js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* klucz */ 'message', /* wartość */ 'hello!')
Wartości dostarczone na poziomie aplikacji są dostępne dla wszystkich komponentów renderowanych w aplikacji. Jest to szczególnie przydatne podczas pisania wtyczek, ponieważ wtyczki zazwyczaj nie mogłyby dostarczać wartości za pomocą komponentów.
Wstrzykiwanie (Inject)
Aby wstrzyknąć dane dostarczone przez komponent nadrzędny, użyj funkcji inject()
:
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
Jeśli dostarczona wartość jest referencją (ref), zostanie wstrzyknięta bez zmian i nie zostanie automatycznie rozpakowana. Pozwala to komponentowi wstrzykującemu zachować połączenie reaktywności z komponentem dostarczającym.
Pełny przykład provide + inject z reaktywnością
Ponownie, jeśli nie używasz <script setup>
, inject()
powinno być wywoływane tylko synchronicznie wewnątrz setup()
:
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}
Domyślne wartości wstrzyknięć
By default, inject
assumes that the injected key is provided somewhere in the parent chain. In the case where the key is not provided, there will be a runtime warning.
If we want to make an injected property work with optional providers, we need to declare a default value, similar to props:
js
// `value` przyjmie wartość "domyślna wartość"
// jeśli nie zostanie dodana wartość dla "message"
const value = inject('message', 'domyślna wartość')
W niektórych przypadkach wartość domyślna może wymagać utworzenia poprzez wywołanie funkcji lub utworzenie nowej instancji klasy. Aby uniknąć niepotrzebnych obliczeń lub efektów ubocznych w przypadku, gdy opcjonalna wartość nie jest używana, możemy użyć funkcji fabrykującej do utworzenia wartości domyślnej:
js
const value = inject('key', () => new ExpensiveClass(), true)
Trzeci parametr wskazuje, że wartość domyślna powinna być traktowana jako funkcja fabrykująca.
Praca z reaktywnością
Podczas używania reaktywnych wartości provide / inject, zaleca się, aby wszelkie mutacje stanu reaktywnego były wykonywane wewnątrz dostawcy zawsze, gdy jest to możliwe. Zapewnia to, że dostarczany stan i jego możliwe mutacje są umiejscowione w tym samym komponencie, co ułatwia późniejsze utrzymanie kodu.
Mogą zdarzyć się sytuacje, gdy potrzebujemy zaktualizować dane z komponentu wstrzykującego. W takich przypadkach zalecamy dostarczenie funkcji, która jest odpowiedzialna za mutację stanu:
vue
<!-- wewnątrz komponentu dostarczającego -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('North Pole')
function updateLocation() {
location.value = 'South Pole'
}
provide('location', {
location,
updateLocation
})
</script>
vue
<!-- wewnątrz komponentu wstrzykującego -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>
Ostatecznie, możesz opakować dostarczoną wartość za pomocą readonly()
jeśli chcesz mieć pewność, że dane przekazywane przez provide
nie mogą być mutowane przez komponent wstrzykujący.
vue
<script setup>
import { ref, provide, readonly } from 'vue'
const count = ref(0)
provide('read-only-count', readonly(count))
</script>
Praca z Symbolami jako kluczami
Do tej pory używaliśmy w przykładach kluczy wstrzykiwania jako ciągów znaków. Jeśli pracujesz nad dużą aplikacją z wieloma dostawcami zależności lub tworzysz komponenty, które będą używane przez innych programistów, najlepiej jest używać kluczy wstrzykiwania typu Symbol, aby uniknąć potencjalnych kolizji.
Zalecane jest eksportowanie Symboli w dedykowanym pliku:
js
// keys.js
export const myInjectionKey = Symbol()
js
// w komopnencie dostarczającym
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, {
/* dane do wstrzyknięcia */
})
js
// w komponencie wstrzykującym
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)
Zobacz także: Typowanie Provide / Inject (Dostarczanie / Wstrzykiwanie)