پراپرتیهای computed
مثال پایه
عباراتی که در تمپلیت استفاده می شوند بسیار راحت هستند، اما برای عملیاتهای ساده طراحی شدهاند. قرار دادن منطق بیش از حد در تمپلیتهای شما ممکن است باعث ناخوانایی و دشواری در نگهداری کدها شود. به عنوان مثال، اگر یک آبجکت با یک آرایه تو در تو داشته باشیم:
js
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
و میخواهیم پیامهای مختلفی را بر اساس اینکه آیا author
قبلاً کتابی داشته یا نه نمایش دهیم:
html
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
در این نقطه، تمپلیت کمی پیچیده شده است. باید وقت بیشتری برای درک کد صرف کنیم که متوجه شویم شرط بر اساس author.books
یک محاسبه انجام میدهد. مهمتر از این، اگر نیاز باشد که این محاسبه را بیش از یک بار در تمپلیت استفاده کنیم، احتمالاً نمیخواهیم یک کد را چندین بار بنویسیم.
به همین دلیل است که وقتی منطق پیچیده و دادههای پویا داریم، استفاده از ویژگی computed (کلمه computed به معنی محاسبه شده است) توصیه میشود. در اینجا همان مثال، بازسازی شده است:
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'
]
})
// a computed ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
</script>
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>
آن را در Playground امتحان کنید
در اینجا یک پراپرتی computed به نام publishedBooksMessage
تعریف کردهایم. تابع computed()
انتظار دارد که یک تابع به عنوان ورودی دریافت کند که مقدار بازگشتی آن از نوع computed ref باشد. مشابه ref های عادی، شما میتوانید به نتیجه محاسبه شده با عنوان publishedBooksMessage.value
دسترسی پیدا کنید. computed ref ها همچنین در تمپلیتها به صورت خودکار باز میشوند، بنابراین میتوانید بدون نیاز به .value
به آنها دسترسی پیدا کنید.
یک پراپرتی computed به طور خودکار وابستگیهای reactive خود را دنبال میکند. Vue میداند که محاسبه publishedBooksMessage
به author.books
وابستگی دارد، بنابراین هنگامی که author.books
تغییر میکند، هر اتصالی که به publishedBooksMessage
وابسته باشد، بهروزرسانی میشود.
همچنین ببینید: Typing Computed
تفاوت کشینگ در computedها و متدها
ممکن است متوجه شده باشید که میتوانیم با فراخوانی یک متد هم به همان نتیجه برسیم.
html
<p>{{ calculateBooksMessage() }}</p>
js
// in component
function calculateBooksMessage() {
return author.books.length > 0 ? 'Yes' : 'No'
}
به جای یک پراپرتی computed، می توانیم همان تابع را به عنوان یک متد تعریف کنیم. نتیجه نهایی این دو رویکرد دقیقاً یکسان است. با این حال، تفاوت این است که پراپرتیهای computed بر اساس وابستگیهای reactive، کش می شوند. یک پراپرتی computed تنها زمانی دوباره ارزیابی می شود که برخی از وابستگی های reactive آن تغییر کرده باشند. این بدان معناست که تا زمانی که author.books
تغییر نکرده باشد، دسترسی به publishedBooksMessage
نتیجه محاسبه قبلی را برمی گرداند، بدون نیاز به اجرای مجدد تابع getter .
این به این معنی هم هست که پراپرتی computed زیر هیچ وقت بهروز نمیشود، زیرا Date.now()
یک reactive نمیباشد.
js
const now = computed(() => Date.now())
در مقایسه، متد همیشه هر زمان که رندر مجدد اتفاق بیفتد، فراخوانی میشود.
چرا به کش نیاز داریم؟ تصور کنید ما یک لیست داریم که یک پراپرتی computed دارد که نیاز به انجام محاسبات زیادی دارد. سپس ممکن است پراپرتیهای computed دیگری داشته باشیم که به نوبه خود به این لیست وابسته باشند. بدون کش، ما تابع دریافت کننده لیست را بیشتر از تعداد مورد نیاز اجرا میکنیم! در مواردی که نیاز به کش ندارید، به جای آن از فراخوانی متد استفاده کنید.
computed قابل تغییر
پراپرتیهای computed به طور پیشفرض فقط امکان باز گرداندن داده را دارند. اگر سعی کنید مقدار جدیدی به یک پراپرتی computed اختصاص دهید، یک هشدار در زمان اجرا دریافت خواهید کرد. در موارد نادری که نیاز به "پراپرتی computed قابل تغییر" دارید، میتوانید با ارائه همزمان یک تابع getter و یک تابع setter برای آن، یکی ایجاد کنید.
vue
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
const fullName = computed({
// getter
get() {
return firstName.value + ' ' + lastName.value
},
// setter
set(newValue) {
// Note: we are using destructuring assignment syntax here.
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>
وقتی شما دستور fullName.value = 'John Doe'
را اجرا کنید، تابع setter فراخوانی خواهد شد و firstName
و lastName
بهطور متناسب بهروزرسانی میشوند.
بهترین شیوهها
توابع getter باید فقط مقدار مورد نظر را برگردانند و تغییر دیگری در برنامه ایجاد نکنند.
مهم است به یاد داشته باشید که توابع getter در computed فقط باید محاسبات خالص را انجام دهند. به عبارت دیگر، درون تابع getter، دیگر stateها را تغییر ندهید، از درخواستهای async یا تغییر DOM استفاده نکنید! به ویژگی computed به عنوان یک راه ساده برای محاسبه یک مقدار بر اساس مقادیر دیگر نگاه کنید - مسئولیت اصلی آن تنها محاسبه و بازگرداندن آن مقدار میباشد. در ادامه این بخش، به بحث در مورد انجام عملیات هایی در پاسخ به تغییرات state با ناظرها (watchers) خواهیم پرداخت.
مقادیر computed را تغییر ندهید
مقدار بازگشتی از پراپرتی computed بر اساس مقادیر دیگر محاسبه میشود. به عنوان یک عکس العمل موقت فکر کنید - هر بار که وضعیت مبدأ تغییر میکند، یک عکس العمل جدید ایجاد میشود. تغییر دادن یک عکس العمل موقت معنی ندارد، مقدار بازگشتی باید فقط خوانده شود و روی آن عملیاتی انجام نشود. برای تغییر مقدار بازگشتی، باید منبعی را که پراپرتی computed به آن وابسته است بهروز کنید.