2024-09-13|閱讀時間 ‧ 約 22 分鐘

EP5 - 計算屬性

Computed Properties 計算屬性,顧名思義是可以計算的屬性?
有時候想想為什麼各種框架會被發明出來~
裡頭的特性應該是要用來解決什麼問題的吧?

這篇有影片可以看耶!

基本範例 - Basic Example

在模板中使用表達式非常方便,但它們適用於簡單的操作。將過多的邏輯放在模板中會使其變得臃腫且難以維護。例如,如果我們有一個包含嵌套數組的物件:

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>
</template>

此時,模板開始變得有點混亂。我們需要稍微看一下才能意識到它根據 author.books 進行計算。更重要的是,如果我們需要在模板中多次包含這計算,不希望重複寫邏輯吧。

這就是為什麼在包含響應式數據的複雜邏輯中,推薦使用計算屬性的原因。以下是相同的範例,重構後的版本:

<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 ? 'Yes' : 'No'
})
</script>

<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>

Try it in the Playground

在這裡,我們聲明了一個計算屬性 publishedBooksMessagecomputed() 函數期望接收一個 getter 函數,並且返回一個計算 ref。類似於普通的 ref,你可以通過 publishedBooksMessage.value 訪問計算結果。計算 ref 也會在模板中自動解包,因此你可以在模板表達式中引用它們而不需要 .value

計算屬性會自動追蹤其響應式依賴項。Vue 知道 publishedBooksMessage 的計算依賴於 author.books,因此當 author.books 改變時,它會更新任何依賴 publishedBooksMessage 的綁定。

相關閱讀:計算屬性的類型化

計算緩存 vs 方法 - Computed Caching vs. Methods

你可能已經注意到,我們可以通過在表達式中調用方法來達到相同的結果:

<template>
<p>{{ calculateBooksMessage() }}</p>
</template>

<script>
// 在組件中
function calculateBooksMessage() {
return author.books.length > 0 ? 'Yes' : 'No'
}
</script>

與計算屬性相比,我們可以將相同的函數定義為一個方法。對於最終結果,這兩種方法確實完全相同。然而,區別在於計算屬性是基於其響應式依賴項進行緩存的。計算屬性僅會在某些響應式依賴項發生變化時重新計算。這意味著只要 author.books 沒有改變,對 publishedBooksMessage 的多次訪問將立即返回之前計算的結果,而無需再次運行 getter 函數。

這也意味著以下計算屬性永遠不會更新,因為 Date.now() 不是響應式依賴項

const now = computed(() => Date.now())

相比之下,每次重新渲染時,方法調用都會執行函數。

為什麼我們需要緩存?

想像一下我們有一個昂貴的計算屬性 list,它需要遍歷一個巨大的數組並進行大量計算。然後,我們可能會有其他依賴於 list 的計算屬性。如果沒有緩存,我們將多次不必要地執行 list 的 getter 函數!在不需要緩存的情況下,請使用方法調用。

  • 方法調用:每次重新渲染時都會執行方法,即使方法的依賴數據沒有變化。這樣可能會導致性能問題,特別是當方法執行時間較長時。
  • 計算屬性:僅在依賴數據變化時重新計算,否則返回緩存的結果。這可以提高性能,避免不必要的計算。

可寫入的計算屬性 - Writable Computed

計算屬性預設是僅有 getter 的。如果你嘗試給計算屬性賦予一個新值,會收到一個運行時警告。在極少數情況下,如果你需要一個「可寫入的」計算屬性,可以通過提供 getter 和 setter 來創建一個:

<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) {
// 注意:這裡我們使用了解構賦值語法。
[firstName.value, lastName.value] = newValue.split(' ')
}
})
</script>

現在當你運行 fullName.value = 'John Doe' 時,setter 會被調用並且 firstNamelastName 會相應地更新。

最佳練習 - Best Practices

Getter 應該沒有副作用 - Getters should be side-effect free

請記住,計算屬性的 getter 函數應該僅執行純計算且沒有副作用。例如,不要在計算屬性的 getter 中修改其他狀態、發起異步請求或修改 DOM!可以將計算屬性視為聲明式地描述如何根據其他值來衍生成另一個值,它唯一責任應該是計算並返回該值。在文件的後面部分,我們將討論如何在狀態變更時使用監視器(watchers)來產生副作用。

有趣的範例 Try it in the Playground

避免修改計算屬性的值 - Avoid mutating computed value

從計算屬性返回值是衍生狀態。可以將其視為一個臨時快照,每當源狀態變化時,就會創建一個新的快照。修改快照沒有意義,所以計算屬性的返回值應被視為只讀且永遠不應該被修改,相反,應更新它所依賴的來源狀態來觸發新的計算。

這章節有看得比較懂一點了~
那些不用去F5刷新網頁就可以更新畫面的東東
應該就是類似這種來源更新,畫面自動會更新東東吧 www



分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.