Звільніться від буріння Vue Prop за допомогою Provide/Inject

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

Vue надає механізм “надання/впровадження” (provide/inject), елегантне рішення для уникнення “прокидання пропсів”. “Надання/впровадження” допомагає організувати обмін інформацією між батьківськими та глибоко вкладеними дочірніми компонентами.

Розуміння проблеми “прокидання пропсів”

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

Проміжні компоненти в цій ієрархії повинні отримувати та пересилати ці дані, навіть якщо самі вони їх не використовують. Для передачі даних від батьківського компонента до дочірнього необхідно використовувати атрибути (props) у компонентах Vue.

Розглянемо приклад ієрархії компонентів:

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

Що таке “Надання/Впровадження” (Provide/Inject)?

Vue вирішує цю проблему за допомогою механізму “надання/впровадження”, який дозволяє компоненту-батьку надавати дані або функції своїм компонентам-нащадкам, незалежно від глибини їхнього вкладення. Такий підхід спрощує обмін даними та покращує організацію коду.

Компонент-постачальник

Компонент-постачальник (provider) призначений для поширення даних або методів серед своїх нащадків. Він використовує опцію “provide”, щоб зробити ці дані доступними для своїх дочірніх компонентів. Ось приклад компонента-постачальника:

 
<template>
  <div>
    
    <ParentComponent/>
  </div>
</template>
<script setup>
import { provide } from 'vue';
import ParentComponent from './components/ParentComponent.vue';

const greeting = 'Привіт від провайдера';

provide('greeting', greeting);
</script>

Цей фрагмент коду демонструє компонент-постачальник App, який надає змінну `greeting` усім своїм компонентам-нащадкам. Щоб надати змінну, потрібно вказати ключ. Використання ключа, ідентичного імені змінної, полегшить підтримку вашого коду.

Компоненти-нащадки

Компоненти-нащадки (descendant) — це компоненти, які розташовані в ієрархії вкладення. Вони можуть впроваджувати (inject) та використовувати надані дані у своєму компоненті. Ось як це реалізується:

 <script setup>
import { inject } from 'vue';

const injectedData = inject('greeting');
</script>

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

Зверніть увагу на зображення нижче:

На цьому зображенні показано ієрархію з чотирьох компонентів, починаючи з кореневого компонента, який є відправною точкою. Інші компоненти вкладені в ієрархію, завершуючи компонентом GrandChild.

Компонент GrandChild отримує дані, надані компонентом App. За допомогою цього механізму ви можете уникнути передачі даних через батьківський і дочірній компоненти, оскільки ці компоненти не потребують даних для своєї коректної роботи.

Надання даних на глобальному рівні програми

Ви можете надавати дані на рівні програми, використовуючи “provide/inject” у Vue. Це є звичайним випадком використання для обміну даними та конфігурацією між різними компонентами вашої програми Vue.

Ось приклад того, як ви можете надати дані на рівні програми:

 
import { createApp } from 'vue'
import App from './App.vue'

const globalConfig = {
  apiUrl: 'https://example.com/api',
  authKey: 'my-secret-key',
  
};

app.provide('globalConfig', globalConfig);

createApp(App).mount('#app')

Припустимо, що у вас є програма, якій потрібен об’єкт глобальної конфігурації, що містить адреси API, дані для аутентифікації користувача та інші налаштування.

Ви можете цього досягти, надавши дані конфігурації на рівні кореневого компонента, зазвичай у вашому файлі main.js, дозволяючи іншим компонентам впроваджувати та використовувати їх:

 <template>
  <div>
    <h1>Налаштування API</h1>
    <p>URL API: {{ globalConfig.apiUrl }}</p>
    <p>Ключ аутентифікації: {{ globalConfig.authKey }}</p>
  </div>
</template>
<script setup>
import { inject } from 'vue';

const globalConfig = inject('globalConfig');
</script>

Наведений вище компонент використовує функцію “inject” для отримання доступу до об’єкта `globalConfig`, який надається програмою на глобальному рівні. Ви можете отримати доступ до будь-яких властивостей або налаштувань з `globalConfig`, використовуючи інтерполяцію або зв’язування даних у Vue в межах компонента.

Переваги та сфери застосування “Надання/Впровадження”

Ось деякі переваги та важливі сфери застосування механізму “надання/впровадження” під час створення веб-додатків у Vue.

Чистіший та оптимізований код

Використовуючи “provide/inject”, ви усуваєте необхідність передачі даних проміжними компонентами, які їх не використовують. Це призводить до більш чистого та зручного коду завдяки зменшенню непотрібних оголошень пропсів.

Крім того, система реактивності Vue гарантує, що компоненти перемальовуються лише тоді, коли змінюються їхні залежності. “Provide/inject” дозволяє ефективно обмінюватися даними, що може сприяти оптимізації продуктивності за рахунок зменшення непотрібних перемалювань.

Покращена інкапсуляція компонентів

“Provide/inject” сприяє кращій інкапсуляції компонентів. Дочірні компоненти повинні турбуватися лише про дані, які вони безпосередньо використовують, зменшуючи їхню залежність від конкретної структури даних батьківських компонентів.

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

Ін’єкція залежностей

“Provide/inject” може слугувати простою формою ін’єкції залежностей, роблячи глобальні служби та налаштування, наприклад клієнти API, адреси ресурсів, налаштування користувача або сховища даних, доступними для будь-якого компонента, який їх потребує. Це забезпечує послідовність конфігурацій у вашій програмі.

Основні моменти, які слід враховувати під час використання “Надання/Впровадження”

Хоча механізм “надання/впровадження” має багато переваг, його слід використовувати обережно, щоб уникнути небажаних побічних ефектів.

  • Використовуйте “provide/inject” для обміну важливими даними або функціями, необхідними в ієрархії компонентів, наприклад конфігурацією або ключами API. Надмірне його використання може зробити зв’язки між компонентами надто складними.
  • Документуйте, що надає компонент-постачальник і які компоненти-нащадки повинні впроваджувати. Це допоможе в розумінні та підтримці ваших компонентів, особливо при командній роботі.
  • Будьте обережні щодо створення циклів залежностей, коли дочірній компонент надає те, що впроваджує батьківський компонент. Це призведе до помилок та неочікуваної поведінки.

Чи є “Provide/Inject” найкращим варіантом для управління станом у Vue?

“Provide/inject” є корисним інструментом у Vue для організації потоку даних та управління станом компонентів. Однак “provide/inject” має свої обмеження. Його використання може спричинити проблеми з налагодженням, тестуванням та підтримкою великомасштабних програм.

Використання Pinia, офіційної системи керування станом Vue, було б кращим для обробки складного стану у вашій програмі Vue. Pinia забезпечує централізоване сховище та безпечний підхід до управління станом, що робить розробку програм на Vue більш зрозумілою.