Надавання / введення
На цій сторінці передбачається, що ви вже прочитали основи компонентів. Прочитайте це спочатку, якщо ви новачок у компонентах.
Прокидання реквізитів
Зазвичай, коли нам потрібно передати дані від батьківського до дочірнього компонента, ми використовуємо реквізити. Однак уявіть випадок, коли у нас є велике дерево компонентів, а глибоко вкладеному компоненту потрібне щось із компонента-предка. Маючи лише атрибути, ми мали б передати один і той самий атрибут по всьому батьківському ланцюжку:
Зауважте, хоча компонент <Footer>
може взагалі не піклуватися про ці атрибути, йому все одно потрібно оголосити та передати їх, щоб <DeepChild>
міг отримати до них доступ. Якщо є довший батьківський ланцюг, більше компонентів буде задіяно на цьому шляху. Це називається «прокиданням реквізиту», і мати справу з ним точно нецікаво.
Ми можемо вирішити прокидання реквізитів за допомогою provide
і inject
. Батьківський компонент може служити постачальником залежностей для всіх своїх нащадків. Будь-який компонент у нащадковому дереві, незалежно від того, наскільки він глибокий, може надавати залежності, пропоновані компонентами в його батьківському ланцюжку.
Надавання
Щоб надати дані нащадкам компонента, скористайтеся функцією provide()
:
vue
<script setup>
import { provide } from 'vue'
provide(/* ключ */ 'message', /* значення */ 'привіт!')
</script>
Якщо не використовується <script setup>
, переконайтеся, що provide()
викликається синхронно в setup()
:
js
import { provide } from 'vue'
export default {
setup() {
provide(/* ключ */ 'message', /* значення */ 'привіт!')
}
}
Функція provide()
приймає два аргументи. Перший аргумент називається ключем введення, який може бути рядком або Symbol
. Ключ введення використовується компонентами-нащадками для пошуку потрібного значення для введення. Один компонент може викликати provide()
кілька разів з різними ключами введення, щоб надати різні значення.
Другим аргументом є надане значення. Значення може бути будь-якого типу, включаючи реактивний стан, наприклад референція:
js
import { ref, provide } from 'vue'
const count = ref(0)
provide('key', count)
Надання реактивних значень дозволяє компонентам-нащадкам, використовуючи надане значення, встановити реактивне з'єднання з компонентом-провайдером.
Надання на рівні програми
Окрім надання даних у компоненті, ми також можемо надати на рівні програми:
js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* ключ */ 'message', /* значення */ 'привіт!')
Надавання на рівні програми доступне для всіх компонентів програми. Це особливо корисно під час написання плагінів, оскільки плагіни зазвичай не можуть надавати значення за допомогою компонентів.
Введення
Щоб ввести дані, надані компонентом-предком, скористайтеся функцією inject()
:
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
Якщо надане значення є референцію, воно буде введено як є і не буде автоматично розгорнуто. Це дозволяє компоненту-приймачу зберігати реактивний зв'язок з компонентом-надавачем.
Повний приклад реактивного надавання та введення
Знову ж таки, якщо не використовується <script setup>
, inject()
має викликатися лише синхронно в setup()
:
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}
Стандартні значення введення
За промовчанням inject
передбачає, що введений ключ надано десь у батьківському ланцюжку. Якщо ключ не надано, з'явиться попередження під час виконання.
Якщо ми хочемо, щоб введена властивість працювала з додатковими надавачами, нам потрібно оголосити значення за промовчанням, подібне до реквізитів:
js
// `value` буде "значенням за промовчанням"
// якщо не було надано жодних даних, що відповідають "message".
const value = inject('message', 'значенням за промовчанням')
У деяких випадках може знадобитися створити значення за промовчанням шляхом виклику функції або створення екземпляра нового класу. Щоб уникнути непотрібних обчислень або побічних ефектів у випадку, якщо необов'язкове значення не використовується, ми можемо використовувати фабричну функцію для створення значення за замовчуванням:
js
const value = inject('key', () => new ExpensiveClass(), true)
Третій параметр вказує, що значення за замовчуванням слід розглядати як фабричну функцію.
Робота з реактивністю
Під час використання реактивних значень надавання та введення рекомендується зберігати будь-які мутації реактивного стану всередині надавача, наскільки це можливо. Це гарантує, що наданий стан і його можливі мутації розташовані в одному компоненті, що полегшує його підтримку в майбутньому.
Бувають випадки, коли нам потрібно оновити дані з компонента-приймача. У таких випадках ми рекомендуємо надати функцію, яка відповідає за зміну стану:
vue
<!-- всередині компонента провайдера -->
<script setup>
import { provide, ref } from 'vue'
const location = ref('Північний полюс')
function updateLocation() {
location.value = 'Південний полюс'
}
provide('location', {
location,
updateLocation
})
</script>
vue
<!-- всередині компонента-приймача -->
<script setup>
import { inject } from 'vue'
const { location, updateLocation } = inject('location')
</script>
<template>
<button @click="updateLocation">{{ location }}</button>
</template>
Нарешті, ви можете обернути надане значення за допомогою readonly()
, якщо ви хочете переконатися, що дані, передані через provide
, не можуть бути змінені компонентом-приймачем.
vue
<script setup>
import { ref, provide, readonly } from 'vue'
const count = ref(0)
provide('read-only-count', readonly(count))
</script>
Робота з ключами типу Symbol
Досі ми використовували ключі введення рядків у прикладах. Якщо ви працюєте у великій програмі з багатьма залежними надавачами або створюєте компоненти, які будуть використовуватися іншими розробниками, найкраще використовувати ключі введення типу Symbol, щоб уникнути можливих зіткнень.
Рекомендовано експортувати ключі типу Symbol в окремий файл:
js
// keys.js
export const myInjectionKey = Symbol()
js
// у компоненті-надавачі
import { provide } from 'vue'
import { myInjectionKey } from './keys.js'
provide(myInjectionKey, {
/* дані для надання */
})
js
// в компоненті-приймачі
import { inject } from 'vue'
import { myInjectionKey } from './keys.js'
const injected = inject(myInjectionKey)
Дивіться також: типізація надавання / введення