#vue
#javascript
#frontend
Day 5: Computed Properties & Watchers
Welcome to Day 5! We have data, and we have inputs. Often, we need to display a derived version of that data (e.g., filtering a list, formatting a price).
Computed Properties
A Computed Property is a piece of state that depends on other state.
Why not just a function?
You could use a function like getFullName().
- Function: Runs every time the component re-renders.
- Computed: Cached. It only re-runs if its dependencies (the refs inside it) change.
<script setup lang="ts">
import { ref, computed } from 'vue'
const firstName = ref('John')
const lastName = ref('Doe')
// Read-only computed
const fullName = computed(() => {
return firstName.value + ' ' + lastName.value
})
// Use it just like a ref in template (no .value needed in template)
</script>
<template>
<p>Full Name: {{ fullName }}</p>
</template>
Writable Computed
Rarely, you might need a โsetterโ.
const fullName = computed({
get() { return firstName.value + ' ' + lastName.value },
set(newValue) {
[firstName.value, lastName.value] = newValue.split(' ')
}
})
Watchers
Computed properties are for calculating values. Watchers are for side effects (fetching data, changing the DOM manually, logging).
<script setup lang="ts">
import { ref, watch } from 'vue'
const question = ref('')
const answer = ref('Ask a question...')
// Watch 'question' ref.
watch(question, async (newQuestion, oldQuestion) => {
if (newQuestion.includes('?')) {
answer.value = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
const json = await res.json()
answer.value = json.answer
} catch (e) {
answer.value = 'Error! could not reach the API.'
}
}
})
</script>
<template>
<p>Ask a Yes/No question:</p>
<input v-model="question" />
<p>{{ answer }}</p>
</template>
watchEffect
If you want the watcher to run immediately and automatically track dependencies without listing them:
import { watchEffect } from 'vue'
watchEffect(() => {
console.log(`Current question is: ${question.value}`)
})
Challenge for Day 5
- Create a
searchinput (text). - Create a list of 5 items (e.g., fruits).
- Create a
computedpropertyfilteredListthat returns items matching the search. - Display the
filteredList.
Solution:
<script setup lang="ts">
import { ref, computed } from 'vue'
const search = ref('')
const fruits = ref(['Apple', 'Banana', 'Orange', 'Mango', 'Pear'])
const filteredFruits = computed(() => {
return fruits.value.filter(fruit =>
fruit.toLowerCase().includes(search.value.toLowerCase())
)
})
</script>
<template>
<input v-model="search" placeholder="Search fruits..." />
<ul>
<li v-for="fruit in filteredFruits" :key="fruit">{{ fruit }}</li>
</ul>
</template>
Mastering computed is the key to clean Vue code. If your template looks complex, turn it into a computed property. Tomorrow, we peek under the hood at Lifecycle Hooks.