پراپرتیهای 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()
انتظار دارد که یک getter function به عنوان ورودی دریافت کند که مقدار بازگشتی آن از نوع 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
بهطور متناسب بهروزرسانی میشوند.
دریافت مقدار قبلی
- فقط در نسخه 3.4+ پشتیبانی میشود
در صورتی که نیاز داشته باشید، میتوانید مقدار قبلی برگردانده شده توسط پراپرتی computed را با دسترسی به آرگومان اول تابع getter دریافت کنید:
vue
<script setup>
import { ref, computed } from 'vue'
const count = ref(2)
// را زمانی برمیگرداند که کمتر یا مساوی 3 باشد count مقدار computed این
// باشد، آخرین مقداری که شرط ما را برآورده کرده است، برگردانده می شود count >=4 وقتی
// کمتر یا مساوی 3 شود count تا زمانی که
const alwaysSmall = computed((previous) => {
if (count.value <= 3) {
return count.value
}
return previous
})
</script>
در صورتی که از computed قابل تغییر استفاده می کنید:
vue
<script setup>
import { ref, computed } from 'vue'
const count = ref(2)
const alwaysSmall = computed({
get(previous) {
if (count.value <= 3) {
return count.value
}
return previous
},
set(newValue) {
count.value = newValue * 2
}
})
</script>
بهترین شیوهها
توابع getter باید فقط مقدار مورد نظر را برگردانند و تغییر دیگری در برنامه ایجاد نکنند.
مهم است به یاد داشته باشید که توابع getter در computed فقط باید محاسبات خالص را انجام دهند. به عبارت دیگر، درون تابع getter، دیگر stateها را تغییر ندهید، از درخواستهای async یا تغییر DOM استفاده نکنید! به computed به عنوان یک راه ساده برای محاسبه یک مقدار بر اساس مقادیر دیگر نگاه کنید - مسئولیت اصلی آن تنها محاسبه و بازگرداندن آن مقدار میباشد. در ادامه این فصل، به بحث در مورد انجام عملیاتهایی در پاسخ به تغییرات state با ناظرها (watchers) خواهیم پرداخت.
مقادیر computed را تغییر ندهید
مقدار بازگشتی از پراپرتی computed بر اساس مقادیر دیگر محاسبه میشود. به آن مانند یک عکس العمل موقت فکر کنید - هر بار که وضعیت مبدأ تغییر میکند، یک عکس العمل جدید ایجاد میشود. تغییر دادن یک عکس العمل موقت معنی ندارد، مقدار بازگشتی باید فقط خوانده شود و روی آن عملیاتی انجام نشود. برای تغییر مقدار بازگشتی، باید منبعی که پراپرتی computed به آن وابسته است را بهروز کنید.