小探vue2.6和2.7和3中的setup的初始化时机

由 漆黑菌 于 2023年12月13日 发布

缘起

vue2.6.11 + composition-api setup中无法通过proxy获取computed中定义的值。

2.6.14 + composition-api 行为

从composition-api代码中initSetup(vm, vm.$props)我们可以看到,在beforeCreate时会把initSetup挂在初始化data之前。

从2.6.14的代码中initState,初始化的顺序是,props -> method -> (initSetup) data -> computed -> watch

Vue.prototype._init中可以看到,initState是在 beforeCreate -> initInjections 之后,initProvide -> created之前

所以理论上在2.6.14中setup只能拿到inject props和method

亲测在2.6.14 setup 中执行

    const { proxy } = getCurrentInstance();
    console.log("vue version", version);
    console.log("props testProps", proxy.testProps);
    console.log("method testMethod", proxy.testMethod);
    console.log("method testData", proxy.testData);
    console.log("method testComputed", proxy.testComputed);

    onMounted(() => {
      console.log("onMounted");
      console.log("props testProps", proxy.testProps);
      console.log("method testMethod", proxy.testMethod);
      console.log("method testData", proxy.testData);
      console.log("method testComputed", proxy.testComputed);
    });

结果是

vue version 2.6.14
props testProps testProps
method testMethod ƒ () {
      console.log('testMethod')
    }
method testData undefined
method testComputed undefined
onMounted
props testProps testProps
method testMethod ƒ () {
      console.log('testMethod')
    }
method testData testData
method testComputed testComputed

运行结果符合预期

2.7.16 行为

initSetup(vm)export function initMixin可知,2.7中 initState的顺序是props -> initSetup -> method -> data -> computed -> watch

initState和2.6.14一样依然是在 beforeCreate -> initInjections 之后,initProvide -> created之前

所以理论上在2.7.16中setup只能拿到inject和props。

亲测在2.7.16 setup 中执行

    const { proxy } = getCurrentInstance();
    console.log("vue version", version);
    console.log("props testProps", proxy.testProps);
    console.log("method testMethod", proxy.testMethod);
    console.log("method testData", proxy.testData);
    console.log("method testComputed", proxy.testComputed);

    onMounted(() => {
      console.log("onMounted");
      console.log("props testProps", proxy.testProps);
      console.log("method testMethod", proxy.testMethod);
      console.log("method testData", proxy.testData);
      console.log("method testComputed", proxy.testComputed);
    });

结果是

vue version 2.7.16-beta.1
props testProps testProps
method testMethod undefined
method testData undefined
method testComputed undefined
onMounted
props testProps testProps
method testMethod ƒ
method testData testData
method testComputed testComputed

运行结果符合预期

vue3 行为

在vue中options其实是通过setup模拟的,从// resolve props and slots for setup contextsetupComponent可知,在setup前应当初始化了slot和props

setupStatefulComponent可以看到setup初始化的过程

finishComponentSetup中才会调用applyOptions兼容options api。

所以理论上在3.3.11中setup只能拿到props。

亲测在3.3.11 setup 中执行

    const { proxy } = getCurrentInstance();
    console.log("vue version", version);
    console.log("props testProps", proxy.testProps);
    console.log("method testMethod", proxy.testMethod);
    console.log("method testData", proxy.testData);
    console.log("method testComputed", proxy.testComputed);

    onMounted(() => {
      console.log("onMounted");
      console.log("props testProps", proxy.testProps);
      console.log("method testMethod", proxy.testMethod);
      console.log("method testData", proxy.testData);
      console.log("method testComputed", proxy.testComputed);
    });

结果是

vue version 3.3.11
props testProps testProps
method testMethod undefined
method testData undefined
method testComputed undefined
onMounted
props testProps testProps
method testMethod ƒ () {
            console.log('testMethod');
        }
method testData testData
method testComputed testComputed

运行结果符合预期