Vue3.0退出了watchEffect,刚好我的项目应用到了,很好用,然而发现了一个景象:watchEffect没有触发ref的数组变动,间接上代码。

<script setup>import { ref, watchEffect } from 'vue';const list = ref([1,2,3])watchEffect(() => {    console.log(list.value)})setTimeout(() => {    list.value.push(4)}, 5000)</script>

代码执行,setTimeout后,console.log没有从新执行。


为什么呢?
因为网上根本查不到有用的材料,我去翻了源码。找到了起因,上代码(我做了简洁化解决)

function ref(value) {    return createRef(value, false);}
function createRef(rawValue, shallow) {    if (isRef(rawValue)) {        return rawValue;    }    return new RefImpl(rawValue, shallow);}
class RefImpl {    constructor(value, _shallow) {        this._value = _shallow ? value : toReactive(value);    }    get value() {        trackRefValue(this);        return this._value;    }    set value(newVal) {        newVal = this._shallow ? newVal : toRaw(newVal);        if (hasChanged(newVal, this._rawValue)) {            this._rawValue = newVal;            this._value = this._shallow ? newVal : toReactive(newVal);            triggerRefValue(this, newVal);        }    }}

看代码能够看进去,ref理论执行了createRef办法,该办法返回了一个RefImpl的实例。
也就是说,ref理论返回了一个RefImpl的实例。该RefImpl类劫持了get,set,做了解决。
换句话说,ref其实在肯定水平上,是没有应用Proxy的,并不是像网上文章所说:"Vue3其实都在用Proxy,所有数据都是靠Proxy去实现响应的"。(当然,toReactive办法外面应用了)
看到了这一步,咱们发现,其实list是RefImpl的一个实例,这个实例在push过程中,并不会触发set,所以天然无奈执行console.log


那么,新问题来了,为什么不会触发set?
问得好,你能够想一下,为什么咱们用const定义一个数组,再往数组外面加货色,不会报错。


下一个问题,如果,我是上面的代码,会怎么样?

<script setup>import { ref, watchEffect } from 'vue';const list = ref([1,2,3])watchEffect(() => {    console.log(list.value.length) // 加一个length})setTimeout(() => {    list.value.push(4)}, 5000)</script>

watchEffect外面退出了length,其余都不变,你会发现,setTimeout后也会执行console了,这又是为什么?

class RefImpl {    constructor(value, _shallow) {        this._value = _shallow ? value : toReactive(value);         // 答案在这个toReactive外面    }}
const toReactive = (value) => {    return isObject(value) ? reactive(value) : value};

也就是说,toReactive其实是判断了,如果是对象,还会被reactive包裹,reactive外部就是Proxy劫持了get,set。代码我就不贴了,有点长
也就是说,list的[1,2,3,4],被Proxy劫持了,被get和set都会有执行对应的回调。当第一次获取length的时候触发了Proxy的get,而这个时候watchEffect和Proxy能够了解为绑定了,有了分割,所以之后push的时候,watchEffect就被调用了。
好了,完结撒花。


课外题,watchEffect会这样,那么watch会怎么样?