Reactivity. It's a popular buzzword. It's also one of the most convenient features of front-end frameworks.
What is it exactly, and how does it work in Vue 3?
Prerequisites
- Working Knowledge of basic JavaScript and JS objects
- Working Knowledge of basic Vue.js
What is Reactivity?
Reactivity is a programming paradigm that allows us to adjust to changes in a declarative manner.
Vue 3.x documentation
We say a value is reactive when it can update itself in response to changes in values it depends on. What do we mean by depends on?
Let's take an example:
let val1 = 2
let val2 = 3
let sum = val1 + val2
The value of sum is always determined by the values of val1 and val2, so we say that sum depends on val1 and val2.
What happens to sum when one of the values it depends on changes? In regular JavaScript, it stays the same.
console.log(sum) // 5
val1 = 3
console.log(sum) // Still 5
But if sum was reactive:
console.log(sum) // 5
val1 = 3
console.log(sum) // Sum is 6!
The value of sum would change in response to the change in a value it depended on.
What does Vue need to make a value reactive?
Vue needs to know:
- what dependencies that value has.
- when those dependencies change.
Vue also needs to be able to re-calculate values when their dependencies change.
How Vue knows when dependencies change
Vue wraps the data object of all components with an ES6 Proxy.
A proxy is an object that wraps a target object.
This is important because all reactive values depend (directly or not) on the properties in a component's data object.
Proxies allow you to intercept all requests to get or set properties of the target. They also let you run any code in response to those requests.
Thanks to this, when code attempts to change one of the properties of a data object, Vue intercepts it and is aware of it.
Vue can then re-calculate any functions that depend on that value. But how does Vue know which functions depend on which values?
How Vue knows which dependencies belong to a value
To make our value reactive, we need to wrap it in a function. Using sum to illustrate again:
// we need to go from
let val1 = 2
let val2 = 3
let sum = val1 + val2
// to
const updateSum = () => {
sum = val1 + val2
}
Vue then wraps all such functions with an effect. An effect is a function that takes another function as an argument. Vue then calls the effect in place of that function.
When Vue calls an effect, the effect:
- Records that it's running.
- Calls the function it received as an argument.
- Removes itself from the list of running effects after the function ends.
Remember all source values come from a Proxy (the data component)? While executing the function it wraps, the effect will need a property from the data object, and try to read it.
The Proxy will intercept that read request. Vue checks which effect is currently running. It then records that the effect depends on the property it tried to read. This is how Vue knows which values depend on which properties.
So how does Vue know when to re-run the functions that return dependent values?
The answer is once again the magic of Proxies. Proxies can intercept requests to set property values too.
Remember we now have a record of effects, as well as the values they depend on. When the value of a property in data changes, Vue needs to do one thing: check that record and update the source value.
Vue can then re-run all the effects that depend on it, and thus update the values.
Conclusion
This article is a simplified overview of how reactivity works in Vue 3. If you'd like to read more on the subject, here are some resources:
Top comments (4)
This is super cool!
Thanks!
Amazing!!!
Really nice