Imagine a web application so intuitive, it anticipates your users' needs. Data updates flow effortlessly, reflected instantly in a dynamic UI. This isn't just an imagination, it's the cornerstone of Vue.js 3's next-level reactivity system.
Vue.js 3 goes beyond the standard reactive approach, offering a more granular and efficient system for managing your application's state. In this article, we'll unveil the secrets behind Vue.js 3's reactivity magic, empowering you to craft web applications that feel truly alive.
Vue.js 3's reactivity system is a core concept that simplifies building dynamic and responsive user interfaces. It automatically tracks changes in your application's data, ensuring the UI reflects those modifications seamlessly. This eliminates the need for manual DOM manipulation, streamlining development and enhancing maintainability.
At its core, Vue leverages JavaScript's Proxies API to track changes in your data structures. These data structures, specifically objects and arrays, become "reactive" when wrapped using Vue's built-in APIs like ref
and reactive
. Any modifications made to the properties within these reactive structures are automatically detected by Vue, triggering a re-render of the affected components.
Before diving into the details, let's explore why reactivity is valuable:
When it comes to creating reactive data in Vue.js 3, you have two primary tools at your disposal: ref
and reactive
:
ref
: refs are the recommended way to declare reactive state in vue.js. It accepts all data types and we can easily reassign its value to something else. But you have to use .value
to retrieve the stored data.reactive
: Ideal for creating reactive objects or arrays. The stored data can be accessed by using normal data accessors like dot notation .
and square bracket notation []
.Deciding which to use between ref and reactive is completely up to you. Both APIs are achieving reactivity but each has its unique use-cases. But as a rule of thumb, ref is suitable for the majority of use-cases so it’s recommended to just always use ref.
While ref
and reactive
offer a foundational approach to reactivity, Vue provides additional tools for monitoring specific data changes. Here's a brief overview:
watch
: This API or method, allows you to define a callback function that executes whenever a specific reactive property changes.<script setup>
import { ref, watch } from 'vue';
const count = ref(0);
// Using watch to execute a callback when count changes
watch(count, (newValue, oldValue) => {
console.log(`Count changed from ${oldValue} to ${newValue}`);
});
const increment = () => {
count.value++;
};
</script>
In this code example, watch is used to execute a callback whenever the count
reactive property changes. The callback function logs the old and new values of count
whenever it changes.
watchEffect
: Similar to watch
, but it offers more flexibility by allowing you to access multiple reactive dependencies within the callback function.<script setup>
import { ref, watchEffect } from 'vue';
const firstNumber = ref(0);
const secondNumber = ref(0);
const sum = ref(0);
// Using watchEffect to reactively compute the sum of firstNumber and secondNumber
watchEffect(() => {
sum.value = firstNumber.value + secondNumber.value;
});
</script>
In this example, watchEffect is used to reactively compute the sum based on changes to both firstNumber and secondNumber. The callback function inside watchEffect
accesses both firstNumber
and secondNumber
, demonstrating the ability to work with multiple reactive dependencies within the same callback function.
Watch and watchEffect are valuable tools for tracking changes in reactive data, but they're best suited for situations requiring actions beyond their scope. For simple observation of reactive data without triggering side-effects, computed properties offer a more efficient solution.
Computed properties in Vue.js are functions that calculate values based on reactive data sources, such as ref
or reactive
. Whenever these data sources change, computed properties automatically recalculate their values, ensuring that the template reflects the most up-to-date information. This feature eliminates the need for manual calculations, streamlining development and guaranteeing that the UI stays synchronized with the underlying data.
One key advantage of computed properties is their caching mechanism. They only recalculate when their dependencies change. While this feature helps in optimizing performance by avoiding unnecessary computations, it also leads to some limitations.
Let's say we want to craft a real-time clock in Vue.js. Let’s begin by analyzing the provided code snippet using computed properties:
<script setup>
import { computed } from 'vue';
const formattedTime = computed(() => {
const currentTime = Date.now()
const formattedTime = // Logic to get formatted time
return formattedTime;
});
</script>
The computed
property formattedTime
attempts to retrieve the current time using Date.now()
or new Date()
. At the first glimpse, you would think that the computed property will update its value every time Date.now()
has changed. However, there's a catch: computed properties only re-evaluate when their reactive dependencies change.
In this case, both methods (Date.now() and new Date()) are not reactive, meaning Vue doesn't automatically detect changes within them. As a result, the formattedTime
computed property won't update with the current time at regular intervals, rendering the clock static.
Now that we understand the limitations of computed properties in this scenario, let's revisit building the real-time clock using a more suitable approach:
formattedTime
into a Function:formattedTime
from a computed property into a function. This function will return the current time in the desired format.function getFormattedTime() {
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
const formattedTime = `${hours}:${minutes}:${seconds}`;
return formattedTime;
}
ref
named "currentTime" to hold the current time value. This ref
will have the initial value returned from getFormattedTime
function.import { ref } from 'vue';
const currentTime = ref(getFormattedTime());
<template>
<p>{{ currentTime }}</p>
</template>
<script setup>
// logic
</script>
updateClock()
function to update the currentTime
ref with the value returned by the getFormattedTime()
function.const updateClock = () => {
currentTime.value = getFormattedTime();
};
updateClock()
function every second (1000ms).const intervalId = setInterval(updateClock, 1000);
import { onBeforeUnmount } from 'vue';
onBeforeUnmount(() => {
clearInterval(intervalId);
});
And here’s how the final code would look like:
<template>
<h1>Real-Time Clock</h1>
<p>{{ currentTime }}</p>
</template>
<script setup>
import { ref, onBeforeUnmount } from 'vue';
// Gets the current time in a readable format
const getFormattedTime = () => {
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const seconds = now.getSeconds().toString().padStart(2, '0');
const formattedTime = `${hours}:${minutes}:${seconds}`;
return formattedTime;
};
// A variable ref to store the current time
const currentTime = ref(getFormattedTime());
// Updates the variable ref currentTime with getFormattedTime returned value
const updateClock = () => {
currentTime.value = getFormattedTime();
};
// Creates an interval to update currentTime by trigerring updateClock function
const intervalId = setInterval(updateClock, 1000);
// Cleans the interval when component unmounts
onBeforeUnmount(() => {
clearInterval(intervalId);
});
</script>
This article delved into the heart of Vue.js 3: its reactivity system. We explored the fundamentals of ref
and reactive
for managing reactive data, ensuring your UI seamlessly reflects data changes. We distinguished between computed
properties, ideal for deriving values from reactive sources, and watch
/watchEffect
, suited for side effects and complex scenarios.
By building a real-time clock example, we demonstrated the limitations of computed properties with non-reactive data and showcased the correct implementation using refs, functions, and setInterval
to achieve true reactivity.
Feel free to have a look at the complete implementation code here
Ready to take your Vue.js development to the next level? Explore the highly anticipated Vue.js Master Class 2024 on Vue School.
This comprehensive course, built from the ground up, will equip you with:
and more..
Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.
More than 200.000 users have already joined us. You are welcome too!
© All rights reserved. Made with ❤️ by BitterBrains, Inc.