Introduction
Explore the differences between reactive
and shallowReactive
, delving into the concepts of deep reactivity and shallow reactivity in Vue.js.
Shallow Reactivity vs Deep Reactivity
const obj = reactive({ foo: { bar: 1 } })
effect(() =>{
console.log(obj.foo.bar)
})
// Modifying obj.foo.bar value does not trigger reactivity
obj.foo.bar = 2
Initially, an object obj
is created with a property foo
containing another object { bar: 1 }
. When accessing obj.foo.bar
inside an effect function, it is noticed that modifying obj.foo.bar
does not trigger the effect function again. Why does this happen? Let’s take a look at the current implementation:
function reactive(obj) {
return new Proxy(obj ,{
get(target, key, receiver) {
if (key === 'raw')
return target;
track(target, key);
// When reading the property value, return it directly
return Reflect.get(target, key, receiver)
}
// Other trapping functions are omitted
})
}
In the given code, when accessing obj.foo.bar
, it first reads the value of obj.foo
. Here, Reflect.get
is used to directly return the result of obj.foo
. Since the result obtained through Reflect.get
is a plain object, namely { bar: 1 }
, it is not a reactive object. Therefore, when accessing obj.foo.bar
inside the effect function, no reactivity is established. To address this, the result returned by Reflect.get
needs to be wrapped:
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
const result = Reflect.get(target, key, receiver);
// If the result is an object, make it reactive
if (typeof result === 'object') {
return reactive(result);
}
return result;
},
// Other traps...
});
}
In this code snippet, the reactive
function is defined. It takes an object as a parameter and returns a proxy of that object. The proxy uses a get
trap function that triggers when accessing a property of the object. In the get
trap, Reflect.get
is used to retrieve the property value. If the result is an object, it is made reactive by calling the reactive
function recursively. This ensures that nested objects also possess reactive properties, allowing modifications to trigger the reactivity system.
Shallow Reactivity
However, there are scenarios where deep reactivity is not desired, leading to the concept of shallowReactive
or shallow reactivity. Shallow reactivity means that only the top-level properties of an object are reactive. For example:
Suppose we have an object with a nested object as its property:
let obj = {
innerObj: {
key: 'value'
}
}
If we apply deep reactivity to obj
:
let reactiveObj = reactive(obj);
Any modifications to obj
or innerObj
properties will trigger the reactivity system:
reactiveObj.innerObj.key = 'new value'; // Triggers reactivity
However, if we want only the top-level properties of obj
to be reactive, meaning modifications to obj
trigger reactivity but modifications to innerObj
do not, we use the shallowReactive
function:
let shallowReactiveObj = shallowReactive(obj);
With shallowReactive
, only modifications to obj
will trigger reactivity:
shallowReactiveObj.innerObj = {}; // Triggers reactivity
shallowReactiveObj.innerObj.key = 'new value'; // Does not trigger reactivity
Vue.js and reactive
vs shallowReactive
In Vue.js, both reactive
and shallowReactive
functions are used to create reactive objects. Let’s explore their differences.
The reactive
function creates deeply reactive objects. This means that both the object itself and all its nested objects become reactive. Any modifications to the object or its nested objects’ properties will trigger the reactivity system.
On the other hand, the shallowReactive
function creates shallowly reactive objects. This means that only the top-level properties of the object are reactive. If the object contains nested objects, modifications to those nested objects’ properties will not trigger the reactivity system.
let obj = {
innerObj: {
key: 'value'
}
}
let reactiveObj = Vue.reactive(obj);
reactiveObj.innerObj.key = ‘new value’; // Triggers reactivity
let shallowReactiveObj = Vue.shallowReactive(obj);
shallowReactiveObj.innerObj.key = ‘new value’; // Does not trigger reactivity
Readonly and Shallow Readonly
After discussing reactivity and shallow reactivity, let’s talk about readonly and shallow readonly:
Vue.js provides readonly
and shallowReadonly
functions to create readonly reactive objects.
The readonly
function creates deeply readonly reactive objects. This means that both the object itself and all its nested objects are readonly. Any attempts to modify the object or its nested objects’ properties will fail.
The shallowReadonly
function creates shallow readonly reactive objects. This means that only the top-level properties of the object are readonly. If the object contains nested objects, properties of these nested objects can be modified.
let obj = {
innerObj: {
key: 'value'
}
}
let readonlyObj = Vue.readonly(obj);
readonlyObj.innerObj.key = 'new value'; // This will fail because the object is readonly
let shallowReadonlyObj = Vue.shallowReadonly(obj);
shallowReadonlyObj.innerObj.key = 'new value'; // This will succeed because only top-level properties are readonly
Note: This article is a translated version of the original post. For the most accurate and up-to-date information, please refer to the original source.
```
Comments