Skip to content

Надавання / введення ​

На цій сторінці передбачається, що ви вже прочитали основи компонентів. Прочитайте це спочатку, якщо ви новачок у компонентах.

Прокидання реквізитів ​

Зазвичай, коли нам потрібно передати дані від батьківського до дочірнього компонента, ми використовуємо реквізити. Однак уявіть випадок, коли у нас є велике дерево компонентів, а глибоко вкладеному компоненту потрібне щось із компонента-предка. Маючи лише атрибути, ми мали б передати один і той самий атрибут по всьому батьківському ланцюжку:

діаграма прокидання реквізитів

Зауважте, хоча компонент <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)

Надання реактивних значень дозволяє компонентам-нащадкам, використовуючи надане значення, встановити реактивне з'єднання з компонентом-провайдером.

Щоб надати дані нащадкам компонента, скористайтеся параметром provide:

js
export default {
  provide: {
    message: 'привіт!'
  }
}

Для кожної властивості в об'єкті provide ключ використовується дочірніми компонентами для пошуку правильного значення для введення, тоді як значення є тим, що вводиться в кінцевому підсумку.

Якщо нам потрібно надати стан кожного екземпляра, наприклад дані, оголошені за допомогою data(), тоді provide має використовувати значення функції:

js
export default {
  data() {
    return {
      message: 'привіт!'
    }
  },
  provide() {
    // використовуйте синтаксис функції, щоб ми могли отримати доступ до `this`
    return {
      message: this.message
    }
  }
}

Однак зауважте, що це не робить введення реактивним. Нижче ми обговоримо, як зробити введення реактивними.

Надання на рівні програми ​

Окрім надання даних у компоненті, ми також можемо надати на рівні програми:

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
export default {
  inject: ['message'],
  created() {
    console.log(this.message) // введене значення
  }
}

Введення обчислюються перед власним станом компонента, тому ви можете отримати доступ до ввдених властивостей у data():

js
export default {
  inject: ['message'],
  data() {
    return {
      // вихідні дані на основі введеного значення
      fullMessage: this.message
    }
  }
}

Повний приклад надавання та введення

Псевдонім введення ​

У разі використання синтаксису масиву для inject введені властивості відображаються в екземплярі компонента за допомогою того самого ключа. У наведеному вище прикладі властивість було надано в ключі "message" і введено як this.message. Локальний ключ такий самий, як ключ введення.

Якщо ми хочемо ввести властивість за допомогою іншого локального ключа, нам потрібно використовувати синтаксис об'єкта для опції inject:

js
export default {
  inject: {
    /* локальний ключ */ localMessage: {
      from: /* ключ введення */ 'message'
    }
  }
}

Тут компонент знайде властивість, надану ключем "message", а потім представить його як this.localMessage.

Стандартні значення введення ​

За промовчанням inject передбачає, що введений ключ надано десь у батьківському ланцюжку. Якщо ключ не надано, з'явиться попередження під час виконання.

Якщо ми хочемо, щоб введена властивість працювала з додатковими надавачами, нам потрібно оголосити значення за промовчанням, подібне до реквізитів:

js
// `value` буде "значенням за промовчанням"
// якщо не було надано жодних даних, що відповідають "message".
const value = inject('message', 'значенням за промовчанням')

У деяких випадках може знадобитися створити значення за промовчанням шляхом виклику функції або створення екземпляра нового класу. Щоб уникнути непотрібних обчислень або побічних ефектів у випадку, якщо необов'язкове значення не використовується, ми можемо використовувати фабричну функцію для створення значення за замовчуванням:

js
const value = inject('key', () => new ExpensiveClass(), true)

Третій параметр вказує, що значення за замовчуванням слід розглядати як фабричну функцію.

js
export default {
  // необхідний синтаксис об'єкта
  // при оголошенні значень за замовчуванням для надавання
  inject: {
    message: {
      from: 'message', // це необов’язково, якщо для введення використовується той самий ключ
      default: 'значенням за промовчанням'
    },
    user: {
      // використовувати функцію фабрики для непримітивних значень, які є дорогими
      // для створення, або такі, які мають бути унікальними для екземпляра компонента.
      default: () => ({ name: 'Степан' })
    }
  }
}

Робота з реактивністю ​

Під час використання реактивних значень надавання та введення рекомендується зберігати будь-які мутації реактивного стану всередині надавача, наскільки це можливо. Це гарантує, що наданий стан і його можливі мутації розташовані в одному компоненті, що полегшує його підтримку в майбутньому.

Бувають випадки, коли нам потрібно оновити дані з компонента-приймача. У таких випадках ми рекомендуємо надати функцію, яка відповідає за зміну стану:

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>

Щоб введення були зв'язані реактивно із надавачем, нам потрібно надати обчислену властивість за допомогою функції computed():

js
import { computed } from 'vue'

export default {
  data() {
    return {
      message: 'привіт!'
    }
  },
  provide() {
    return {
      // явно надати обчислювану властивість
      message: computed(() => this.message)
    }
  }
}

Повний приклад реактивного надавання та введення

Функція computed() зазвичай використовується в компонентах композиційного API, але також може використовуватися для доповнення певних випадків використання в опційному API. Ви можете дізнатися більше про його використання, прочитавши основи реактивності і обчислювані властивості із вподобанням API, встановленим як Композиційний.

Робота з ключами типу 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)

Дивіться також: типізація надавання / введення

js
// у компоненті-приймачі
import { myInjectionKey } from './keys.js'

export default {
  provide() {
    return {
      [myInjectionKey]: {
        /* дані для надання */
      }
    }
  }
}
js
// в компоненті-приймачі
import { myInjectionKey } from './keys.js'

export default {
  inject: {
    injected: { from: myInjectionKey }
  }
}
Надавання / введення has loaded