提供/注入
本頁面假設您已經閱讀了元件基礎。如果是初次接觸元件,請先閱讀。
屬性鑽取
通常,當我們需要從父元件傳遞資料到子元件時,我們會使用props。但是,想象一下我們有一個龐大的元件樹,並且一個深層巢狀的元件需要從遙遠的祖先元件獲取某些內容。僅使用props,我們可能不得不在整個父鏈上傳遞相同的props
注意,儘管<Footer>
元件可能根本不關心這些props,但它仍然需要宣告並傳遞它們,以便<DeepChild>
可以訪問它們。如果父鏈更長,那麼在傳遞過程中會有更多元件受到影響。這被稱為“屬性鑽取”,並且處理起來絕對不有趣。
我們可以使用provide
和inject
來解決屬性鑽取問題。父元件可以充當所有其後代元件的依賴提供者。後代樹中的任何元件,無論其深度如何,都可以從其父鏈中的元件中注入依賴項。
提供
要將資料提供給元件的後代,請使用provide()
函式
vue
<script setup>
import { provide } from 'vue'
provide(/* key */ 'message', /* value */ 'hello!')
</script>
如果不使用<script setup>
,請確保在setup()
內部同步呼叫provide()
js
import { provide } from 'vue'
export default {
setup() {
provide(/* key */ 'message', /* value */ 'hello!')
}
}
provide()
函式接受兩個引數。第一個引數稱為注入鍵,可以是字串或Symbol
。注入鍵用於後代元件查詢要注入的所需值。單個元件可以使用不同的注入鍵多次呼叫provide()
以提供不同的值。
第二個引數是提供的值。值可以是任何型別,包括像refs這樣的響應式狀態。
js
import { ref, provide } from 'vue'
const count = ref(0)
provide('key', count)
提供響應式值允許使用提供的值的後代元件與提供者元件建立響應式連線。
應用級提供
除了在元件中提供資料外,我們還可以在應用級別提供
js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* key */ 'message', /* value */ 'hello!')
應用級提供適用於應用中渲染的所有元件。這在編寫外掛時特別有用,因為外掛通常無法使用元件提供值。
注入
要注入祖先元件提供的資料,請使用inject()
函式
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
如果提供的值是ref,它將被原樣注入,並且將不會被自動解包。這允許注入元件保留與提供者元件的響應式連線。
再次提醒,如果不使用<script setup>
,則應在setup()
內部同步呼叫inject()
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}
注入預設值
預設情況下,inject
假設注入鍵在父鏈的某個地方提供。如果鍵沒有提供,將會有執行時警告。
如果我們想使注入屬性與可選提供者一起工作,我們需要宣告一個預設值,類似於 props
js
// `value` will be "default value"
// if no data matching "message" was provided
const value = inject('message', 'default value')
在某些情況下,預設值可能需要透過呼叫函式或建立一個新的類來建立。為了避免在可選值未使用時產生不必要的計算或副作用,我們可以使用工廠函式來建立預設值
js
const value = inject('key', () => new ExpensiveClass(), true)
第三個引數表示預設值應被視為工廠函式。
處理響應性
當使用響應式 provide / inject 值時,建議儘可能在 provider 內部進行任何對響應式狀態的修改。這確保了提供的狀態及其可能的修改位於同一組件中,便於未來的維護。
有時我們需要從注入元件更新資料。在這種情況下,我們建議提供一個負責修改狀態的函式
vue
<!-- inside provider component -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('North Pole')
function updateLocation() {
location.value = 'South Pole'
}
provide('location', {
location,
updateLocation
})
</script>
vue
<!-- in injector component -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>
最後,如果您想確保透過 provide
傳遞的資料不能被注入元件修改,可以將提供的值包裹在 readonly()
中
vue
<script setup>
import { ref, provide, readonly } from 'vue'
const count = ref(0)
provide('read-only-count', readonly(count))
</script>
處理符號鍵
到目前為止,我們在示例中一直使用字串注入鍵。如果您正在處理一個具有許多依賴提供者的大型應用程式,或者您正在編寫將被其他開發者使用的元件,最好使用符號注入鍵以避免潛在的衝突。
建議在專用檔案中匯出符號
js
// keys.js
export const myInjectionKey = Symbol()
js
// in provider component
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, {
/* data to provide */
})
js
// in injector component
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)
另請參閱: 型別 Provide / Inject