تزويد / حقن
لقراءة هذه الصفحة يجب عليك أولا الاطلاع على أساسيات المُكونات . ثم العودة إلى هنا.
التمرير العميق للخاصيات
عادةً , عندما نحتاج إلي تمرير بيانات من المُكون الأب إلي المُكون الإبن . نستخدم الخاصيات (Props). لكن تخيل اننا لدينا شجرة كبيرة من المُكونات , و المُكون الحفيد يحتاج إلي بيانات من المُكون الجد الأعلي منه . بإستخدام الخاصيات (Props) فقط , سوف نتمكن من تمرير نفس الخاصية إلي سلسلة الآباء كاملةً لكي ننقلها من المُكون الجد إلي المُكون الحفيد
لاحظ ان علي الرغم من ان المُكون <Footer>
لا يحتاج هذه الخاصيات علي الإطلاق , ولكن لا يزال بحاجة إلي تعريفها و تمريرها حتي يتمكن المُكون <DeepChild>
من الوصول إليها . إذا كان هناك سلسلة من الآباء أطول مُكونات اكثر سيتم تمرير الخاصيات إليها و هي ليس بحاجة لها . و هذا يسمي "التمرير العميق للخاصيات" وبالتأكيد ليس من الجيد فعله
يمكننا حل مشكلة التمرير العميق للخاصيات (Props Drilling) عن طريق إستخدام التزويد و الحقن provide
و inject
. ان يكون المُكون الأب هو مُزود التبعية (dependency provider) لكل المُكونات الأحفاد له . يمكن ان يتم حقن inject أي مُكون في شجرة الأحفاد و الأبناء بغض النظر عن مدي عمق هذا المُكون بالتباعيات المقدمة من المُكونات الأعلي (الآباء او الجدود) في هذه السلسلة
التزويد
لكي نقوم بتوفير البيانات إلي المُكونات الأحفاد , نستخدم دالة ()provide
vue
<script setup>
import { provide } from 'vue'
provide(/* المفتاح */ 'message', /* القيمة */ 'hello!')
</script>
في حالة عدم إستخدام <script setup>
, تأكد من إستدعاء دالة ()provide
بشكل متزامن (Synchronously) بداخل دالة ()setup
js
import { provide } from 'vue'
export default {
setup() {
provide(/* المفتاح */ 'message', /* القيمة */ 'hello!')
}
}
تقبل هذه الدالة ()provide
وسيطين . يمسي الوسيط الأول بمفتاح الحقن injection key , و الذي يمكن ان يكون في هيئة نصاً String أو رمزً Symbol
. يتم إستخدام مفتاح الحقن بواسطة المُكونات الأحفاد للبحث عن القيمة المرغوب الوصول لها . كما يستطيع المُكون الأحادي ان يستدعي الدالة ()provide
عدة مرات لمفاتيح حقن مختلفة لتوفير قيم عديدة يمكن حقنها من قبل المُكونات الأحفاد
الوسيط الثاني هو القيمة المُقدمة . يمكن لهذه القيمة ان تكون من اي نوع , تشمل الحالة التفاعلية مثل refs
js
import { ref, provide } from 'vue'
const count = ref(0)
provide('key', count)
يسمح توفير القيم التفاعلية (Reactive Values) للمُكونات الأحفاد بإنشاء اتصال تفاعلي إلي المكون المُقدم للبيانات
التزويد علي مستوى التطبيق
بالإضافة إلي تزويد البيانات إلي المُكونات , يمكن ايضاً تزويدها علي مستوي التطبيق:
js
import { createApp } from 'vue'
const app = createApp({})
app.provide(/* المفتاح */ 'message', /* القيمة */ 'hello!')
التزويد علي مستوي التطبيق يكون متاح لجميع المُكونات التي تم عرضها (Rendered components) في التطبيق . هذا الشكل مفيد خاصةً في حالة إنشاء إضافات, لأن الإضافات عادةً لن تكون قادرة علي تزويد القيم بإستخدام المُكونات
الحقن
لكي نحقن البيانات التي يوفرها أحد مُكونات الأحفاد, نستخدم دالة ()inject
vue
<script setup>
import { inject } from 'vue'
const message = inject('message')
</script>
في حالة ان القيمة التي تم تزويدها هي قيمة تفاعلية (Ref) , سوف يتم حقنها كما هي و لم يتم تفكيكها تلقائياً . هذا يسمح للمكون الحاقن بالإحتفاظ بالإتصال التفاعلي بين المُكون Provider المزود
مثال كامل للتزويد + الحقن مع الحالة التفاعلية
مرة أخري , في حالة عدم استخدام <script setup>
, يجب إستدعاء دالة ()inject
بشكل متزامن بداخل دالة ()setup
js
import { inject } from 'vue'
export default {
setup() {
const message = inject('message')
return { message }
}
}
القيم الإفتراضية للحقن
بشكل أفتراضي , يفترض inject
ان المفتاح المحقون تم تزويده في مكانً ما في سلسلة الاَباء . لذالك في حالة عدم تزويده سيتم إظهار رسالة تحذير وقت التشغيل
في حالة اننا نريد ان نجعل خاصية الحقن تعمل بشكل اختياري في حالة تم تزويدها أو لا . يجب تعريف قيمة إبتدائية مثل التي في الخاصيات (Props):
js
// 'default value' سوف تكون قيمتها `value`
// "message" في حالة عدم تزويد خاصية بإسم
const value = inject('message', 'default value')
في بعض الحالات , نريد إنشاء القيمة الإبتدائية من خلال إستدعاء دالة أو إستنساخ من كلاس جديد . لتجنب الحسابات الغير ضرورية أو الأثار الجانبية في حالة عدم استخدام القيمة الإختيارية . يمكن ان نستخدم دالة المصنع (Factory Function) لإنشاء القيمة الإبتدائية:
js
const value = inject('key', () => new ExpensiveClass(), true)
The third parameter indicates the default value should be treated as a factory function.
استخدام الصيغ التفاعلية
عند إستخدام قيم تزويد / حقن تفاعلية, من الأفضل الإحتفاظ بأي طفرات (Mutations) في الحالات التفاعلية داخل مُزود provider كلما كان ممكناً
هناك العديد من الاوقات نريد تعديل البيانات من المُكون الحاقن (injector component) . في بعض الأحيان , من الأفضل إضافة دالة مسؤولة عن تغيير الحالة
vue
<!-- داخل مُكون التزويد-->
<script setup>
import { provide, ref } from 'vue'
const location = ref('North Pole')
function updateLocation() {
location.value = 'South Pole'
}
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>
استخدام المفاتيح الرموز Symbols Keys
حتي الأن , لقد قمنا بإستخدام مفاتيح الحقن النصية في الأمثلة السابقة . إذا كنت تعمل علي تطبيق كبير مع العديد من مُزودي التباعية (dependency providers) , أو انت مسؤول عن مُكونات سيتم إستخدامها من قبل مُطورين أخرين , من الأفضل إستخدام مفاتيح الحقن الرموز (Symbol injection keys) لتجنب الصدامات المحتملة
من الأفضل إستخراج الرموز من ملف مخصوص لها:
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)
شاهد أيضاً: الأنواع للتزويد / الحقن