Sonay Kara
Posted on October 6, 2024
Reactivity Fundamentals
Declaring Reactive State
If you want to specify the reactive state in the Composition API, you can use the recommended way ref() function.
Example :
import { ref } from 'vue'
const count = ref(0)
ref() takes the argument and returns it wrapped in a ref object. This object has the .value property. We can use .value to access the reactive value
Example :
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
As seen in the example, we can access the reactive {value: 0} object with console.log(count). We see that the reactive variable defined with Count is an object. as a result ref() takes the argument and returns it wrapped in a ref object.
If you want to access references in a component's template, simply declare and return them from a component setup() function.
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return {
count
}
}
}
<div>{{ count }}</div>
When using setup, there is no need to use .value to access the reactive variable.
Note : setup is a special hook dedicated to the Composition API. I will explain the setup hook in another article.
You can also modify a reference directly in event handlers
<button @click="count++">
{{ count }}
</button>
In this case, it may have occurred to you that for more complex logic, we may not define functions for event handlers. Yes we can do this
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
function increment()
count.value++
}
return {
count,
increment
}
}
}
Now let's use this function
<button @click="increment">
{{ count }}
</button>
If you want a test, codepen
Script Setup
We mentioned the setup at the beginning of the article. Now we will talk about script setup, which is a different and more useful method. Instead of using setup, you can use script setup.
<script setup>
import { ref } from 'vue'
const count = ref(0)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">
{{ count }}
</button>
</template>
Why Refs?
You might be wondering why we need references with .value instead of plain variables. To explain this we need to examine how Vue's reactivity system works.
When you use a reference in a template and then change the value of the reference, Vue automatically detects the change and updates the DOM accordingly. When a component is first created, Vue keeps track of every reference used during creation. Then when a reference mutates, it will trigger a re-render for the components that follow it.
The .value property gives Vue the opportunity to detect when a ref has been accessed or mutated. Under the hood, Vue performs the tracking in its getter, and performs triggering in its setter. Conceptually, you can think of a ref as an object that looks like this.
const myRef = {
_value: 0,
get value() {
track()
return this._value
},
set value(newValue) {
this._value = newValue
trigger()
}
}
Deep Reactivity
Refs can hold any value type, including deeply nested objects, arrays, or JavaScript built-in data structures like Map.
A ref will make its value deeply reactive. This means you can expect changes to be detected even when you mutate nested objects or arrays
import { ref } from 'vue'
const obj = ref({
nested: { count: 0 },
arr: ['foo', 'bar']
})
function mutateDeeply() {
obj.value.nested.count++
obj.value.arr.push('baz')
}
reactive()
There is another way to declare reactive status with the Reactive() API. Unlike ref, which wraps the inner value into a custom object, reactive() makes the object itself reactive
import { reactive } from 'vue'
const state = reactive({ count: 0 })
Usage in template:
<button @click="state.count++">
{{ state.count }}
</button>
Vue is able to intercept the access and mutation of all properties of a reactive object for reactivity tracking and triggering.
Limitations of reactive()
The reactive() API has several limitations
It cannot hold primitive types such as string, number or boolean.
Cannot replace entire object: since Vue's reactivity tracking works over property access, we must always keep the same reference to the reactive object. This means we can't easily "replace" a reactive object because the reactivity connection to the first reference is lost
let state = reactive({ count: 0 })
// the above reference ({ count: 0 }) is no longer being tracked
// (reactivity connection is lost!)
state = reactive({ count: 1 })
- Not destructure-friendly: when we destructure a reactive object's primitive type property into local variables, or when we pass that property into a function, we will lose the reactivity connection:
Due to these limitations, it is recommended to use ref() as the primary API for declarative reactive status
Conclusion
In this article, we examined the reactivity of vue.js Composition API. We learned why reactivity should be used and examined several usage methods.
Posted on October 6, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.