الخاصيات المحسوبة
مثال بسيط
التعبيرات المدمجة في القالب هي طريقة جيدة، لكنها موجهة فقط للعمليات البسيطة. إذا وضعنا الكثير من الشيفرات داخل القالب فإنه سيصبح معقد وصعب الصيانة. على سبيل المثال، إذا كان لدينا كائن مصفوفة متداخلة:
js
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
و نريد عرض رسائل مختلفة بناءً على author
(المؤلف) إذا كان لديه كتب أو لا:
template
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
عند هذه النقطة، يصبح القالب مزدحمًا قليلاً. يجب أن ننظر إليه لوهلة قبل أن ندرك أنه يقوم بحساب معين استنادًا إلى author.books
. و أهم شيء، نحن ربما لا نريد تكرار نفس الحساب إذا كنا بحاجة إلى تضمينه في القالب أكثر من مرة.
لهذا السبب، في المعالجة المعقدة التي تتضمن بيانات تفاعلية متداخلة، يُوصى باستخدام خاصية محسوبة. هذا المثال السابق مع إعادة تصميمه بهاته الخاصية:
vue
<script setup>
import { reactive, computed } from 'vue'
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
//مرجع خاصية محسوبة
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'نعم' : 'لا'
})
</script>
<template>
<p>هل نشر كتبا؟</p>
<span>{{ publishedBooksMessage }}</span>
</template>
هنا صرحنا بخاصية محسوبة مسماة publishedBooksMessage
. تتوقع الدالة ()computed
أن تتلقى دالة محصلة، ويتم إرجاع قيمة ref محسوب. مثل الـrefs العادية، يمكنك الوصول إلى النتيجة المحسوبة باستخدام publishedBooksMessage.value
. تتم إزالة المراجع المحسوبة تلقائيًا في القوالب لذلك يمكنك الإشارة إليها دون value.
في تعبيرات القالب.
خاصية محسوبة تتبع تلقائيًا إعتمادياتها التفاعلية. يعرف Vue أن حساب publishedBooksMessage
يعتمد على author.books
، لذلك سيقوم بتحديث أي ربط يعتمد على publishedBooksMessage
عند تغيير author.books
.
الق نظرة على: إضافة النوع إلى الخاصيات المحسوبة
تخزين بالخاصيات المحسوبة مقابل التوابع
ربما لاحظت أننا يمكننا الوصول إلى نفس النتيجة من خلال استدعاء تابع في التعبير:
template
<p>{{ calculateBooksMessage() }}</p>
js
// داخل المكون
function calculateBooksMessage() {
return author.books.length > 0 ? 'Yes' : 'No'
}
بدلا من خاصية محسوبة، يمكننا تعريف نفس الدالة كتابعة. من أجل الحصول على النتيجة النهائية، فإن كلا الطريقتين تفيان بنفس الغرض. ومع ذلك، فإن الفرق هو أن الخاصيات المحسوبة مخزنة بناءً على إعتمادياتها التفاعلية. ستقوم خاصية محسوبة بإعادة التقييم فقط عندما تتغير بعض إعتمادياتها التفاعلية. هذا يعني أنه بمجرد عدم تغير author.books
، فإن الوصول المتعدد إلى publishedBooksMessage
سيعيد النتيجة المحسوبة مسبقًا بدون الحاجة إلى تشغيل الدالة المحصلة مرة أخرى.
هذا يعني أيضا أن الخاصية المحسوبة التالية لن تَتحيَّن أبدا، لأن ()Date.now
ليست إعتمادية تفاعلية:
js
const now = computed(() => Date.now())
بالمقارنة، استدعاء تابع سيقوم بتشغيل الدالة دائمًا عندما يحدث إعادة التصيير.
لماذا نحتاج إلى التخزين؟ تصور أنه لدينا خاصية محسوبة مُكْلِفة مسماة list
، والتي تتطلب المرور عبر جميع عناصر مصفوفة كبيرة والقيام بالكثير من الحسابات. ثم قد نملك خاصيات محسوبة أخرى تعتمد على list
بدورها. بدون التخزين، سنقوم بتشغيل الدالة المحصلة على list
عدة مرات أكثر من الضروري! في حالات لا تريد التخزين، استدع تابع بدلاً من ذلك.
الخاصيات المحسوبة القابلة للكتابة
الخاصيات المحسوبة غير قابلة للتعيين افتراضيًا. إذا حاولت تعيين قيمة جديدة لخاصية محسوبة، ستحصل على تحذير خلال وقت التشغيل. في الحالات النادرة التي تحتاج إلى خاصية محسوبة "قابلة للكتابة"، يمكنك إنشاء واحدة من خلال توفير الدالتين المُحصِّلة و المعيّنة:
vue
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// مُحصلة
get() {
return firstName.value + ' ' + lastName.value
},
// معيّنة
set(newValue) {
// ملاحظة: استخدمنا هنا صيغة التعيين عن طريق التفكيك.
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>
الآن عندما تقوم بتشغيل 'محمد عبيدي' = this.fullName
سيتم تشغيل المعيّن وسيتم بالتالي تحديث this.firstName
و this.lastName
.
الممارسات الجيّدة
يجب أن تكون الدوال المحصلة خالية من التأثيرات الجانبية
من المهم أن نتذكر أن الدوال المُحصلة يجب أن تقوم فقط بحسابات بحتة وبدون تأثيرات جانبية. على سبيل المثال، لا تقم بطلبات غير متزامنة أو تغيير الـDOM داخل دالة محصلة!. تصور أي خاصية محسوبة كوصف تصريحي لكيفية استخراج قيمة استنادًا إلى قيم أخرى - يجب أن تكون مسؤوليتها فقط حساب القيمة وإرجاعها. في وقت لاحق في هذا الدليل، سنتحدث عن كيفية تنفيذ التأثيرات الجانبية بالرد على تغييرات الحالة باستخدام الخاصيات المراقبة.
تجنب تعيين القيمة المحسوبة
القيمة المُرجعة من خاصية محسوبة هي حالة مشتقة. فكر فيها كلقطة مؤقتة - كلما تغيرت الحالة المصدرية، سيتم إنشاء لقطة جديدة. بديهيا لا يمكن تعديل لقطة، لذا يجب على أي قيمة محسوبة مُرجعة أن تُقرأ فقط وأن لا يتم تعديلها - بدلاً من ذلك، قم بتحديث الحالة المصدرية التي يعتمد عليها لتشغيل حسابات جديدة.