The book continues above, we continue to discuss this topic, I still leave the screenshot of the official website here.
problem thinking
- The deconstructed value is a basic data type and will lose the responsiveness. If it is a reference data type, will it remain responsive?
- Is Lost Responsive doing it for us
vue
internally ?
problem inquiry
Let's write an example first to construct the scene, which is relatively simple.
<script setup>
import { reactive } from "vue";
const state = reactive({
obj: {
name: "zhangsan",
},
});
const handleClick = () => {
const { obj } = state;
obj.name = "lisi";
};
</script>
<template>
<button @click="handleClick">点击切换</button>
<div>{{ state }}</div>
</template>
复制代码
The effect is as follows:
Let's modify the code below:
const handleClick = () => {
const { name } = state.obj;
name = "lisi";
};
复制代码
The effect is as follows:
After the above comparison, it is found that when the deconstructed is a reference object type, it is responsive, and when the basic data type is used, the responsiveness will be lost.
Source code analysis
We put debug on the top code, and then we enter the reactive
method , it receives one target
, and then judges whether it is read-only, and finally returns the return value of the createReactiveObject
method call, and we enter this method.
In this method, some judgments are made, first to judge whether it is an object, if not, return the value.
Then judge whether the identity __v_raw
is already a proxied object, and if so, return it.
The next judgment is that if existingProxy
the proxy has been Proxy, proxyMap
the Proxy object is directly taken out from the data structure, which is a way to improve performance. It can be seen from the code that the Proxy object will be proxyMap.set(target, proxy)
operated , and the proxyMap
call here is WeakMap
the instance of .
Then go down, and then add a whitelist to the objects that can be reactive. Only Object, Array, Map, Set, WeakMap, and WeakSet objects can be reactive.
Finally, Proxy is performed, and only the first layer is Proxy when reactive for the first time. Let's look at the Proxy object after reactive
At this time, the targetType
value is 1, so it will go baseHandlers
. This method createReactiveObject
is the third parameter of the input parameter, that is mutableHandlers
, it contains the common methods of Proxy
createGetter
It is the function executed after calling the get
method . In line 447, we found that if the child item is still an object, it will recursively call reactive
to perform a deep proxy. At this point, we found that the source code did not do anything to the lost response, that is to say, it lost Reactivity is not in Vue but in the Proxy object itself.
Simple implementation
const obj = {
count: 1
};
const proxy = new Proxy(obj, {
get(target, key) {
console.log("get");
return target[key]
},
set(target, key, value) {
console.log("set");
target[key] = value
return true;
}
});
console.log(proxy.count);
复制代码
When we try to read the value, the get
method , and when the value is set, the set
method will be called. If let { count } = proxy; count = 2
destructuring and reassignment will not trigger set
the method call. Then if the destructuring is a reference data type, now let's change the above code:
const obj = {
counter: {
count: 1
}
};
const reactive = (target) => {
return new Proxy(obj, {
get(target, key) {
console.log("get");
if (typeof target[key] === 'object') {
return reactive(target[key]);
}
return target[key]
},
set(target, key, value) {
console.log("set");
target[key] = value
return true;
}
});
}
let {
counter
} = reactive(obj);
counter.count = 2
复制代码
At this time, both get
methods and set
methods will be called, which also confirms our above conclusion,