Vue.js Composition API
The Vue.js Composition API provides a new way of managing reactivity. It is made of a set of Reactive API functions and plus the facility to register lifecycle hooks using imported functions.
In the Vue.js Composition API book, we are taking a look at how to implement this Reactive API from scratch. Then we will implement a master-details functionality.
Chapter 01: Building a Reactive API
We start our learning journey by first understanding what reactivity is how is implemented in Vue 3. Imagine we have a simple state
object and a render
function.
const state = {
message : 'This is a message'
};function render(state){
document
.getElementById('UI')
.innerHTML =
`<span>${state.message}</span>`;
}
Invoking the render(state)
function displays the message in the UI.
render(state);
Now, suppose we modify the message
property of the state
object.
state.message = 'A new message';
The change of the state
object is not reflected in the UI. If we want that to happen we need to invoke again the render
function.
state.message = 'A new message';
render(state);
Proxy
We need a way to detect object changes and call the render
function. The Proxy object can help achieve that.
The proxy object defines custom behavior for operations like getting or setting a property. The next example shows a proxy calling the render
function on property changes.
const reactiveHandler = {
set: function(obj, prop, value) {
obj[prop] = value;
render(obj);
return true;
}
};const state = new Proxy({
message: 'This is a message'
}, reactiveHandler);
The reactiveHandler
provides a handler for setting an object property. The handler changes the property, calls render
with the modified object and returns true
indicating a successful operation.
reactive()
Reactivity in Vue refers to the process of automatically updating the UI when the state object changes.
We can make an object reactive by simply using a new utility function wrapping the proxy call.
function reactive(obj){
return new Proxy(obj, reactiveHandler);
}const state = reactive({
message: 'This is a message'
});
The reactive
function takes an object and returns a new proxy object wrapping it. All the interactions with the object, like setting and getting data, go through the proxy handler.
At this point, there is no need to manually call the render
function when doing a change on the state
object. The following change is reflected in the UI.
state.message = 'A new message';
watchEffect()
This solution has a drawback. It explicitly states the function to be called. We want to be able to detect this subscriber function without explicitly invoking it in the proxy definition.
JavaScript is a single-threaded language. This means that a single function can execute at a specific moment. We can create a utility function that executes this function but also stores it in a variable.
Consider the following watchEffect
utility function.
let currentFunc = null;
function watchEffect(f){
currentFunc = f;
f();
currentFunc = null;
}
watchEffect
takes a function f
. It stores the function in the currentFunc
variable, giving us access to the currently executing function. Then it executes the f
function and resets the currentFunc
variable to null
.
Instead of executing the render(state)
directly, we can call it using the watchEffect
utility.
watchEffect(() => {
render(state);
});
At this point, we have access to the currently executing function in the reactiveHandler
handler.
The get
handler returns the requested property and saves the currently executing function as the subscriber.
The set
handler changes the property and calls the subscriber function registered in the get
handler.
let subscriber = null;
const reactiveHandler = {
get: function (obj, prop) {
if(currentFunc != null){
subscriber = currentFunc;
}
return obj[prop];
},
set: function(obj, prop, value) {
obj[prop] = value;
subscriber(obj);
return true;
}
};
In this example, we don’t need to specify the function to be called when the state changes. The function is automatically detected by wrapping its call inside the watchEffect
utility.
Click here to get a sample of the book.