Subscribe on changes!

使用template模式在属性传递时,若有h函数的执行,则可能会导致异常的报错

avatar
Apr 30th 2023

Vue version

3.3.0-beta.2

Link to minimal reproduction

https://play.vuejs.org/#eNqdV0tz2zYQ/iuwLqJnJEpyHwdWTlK76TSXHlrPdDqWZ8KQkMSaJDggJDt19N+7u3gQIClPGh4kYvFh39hdvkx+bpr4eOCTZLJuM1k0irVcHZo3m7qoGiEVe2GSb9mJbaWo2BSgU7f1C6+EoccLXCAn2N7Umahbxap2x67xeDT9jZelYH8JWeYX08tNvV5oaSAHFopXTZkqDivG1nue5lzS+0atSQhwut5M/hYHlhc5K9TFZsIWGr1w8PXC8ZnMJnc3B6VEbY0LRXyiPZaozw0HxvgHHKUocaU3Yf0uK4vsESiivsW3zYROw3k1r0XOWQJ2Kl4rgBTweqtXTjcAtk1as+O82Dq+DmQgo9x60I7fAhkawzUoNJzcaQJZpjV6TbUky4YTz2aiag6K5zNcKPEH37b0mvNtUfP3VaH89S2gRQ2KEG3H1e1BSlh+gBindcaJDFGm/z39Qg7dlCJ7vJNp9ljUOyD6GfSTU+fud7Tc5hCt4n9aD3ADDO5E8wF842AejTIO0Dbl6rTikHMf1Vx75yPt8WfiBeakh5L+fbMi8gmeJN3ROURvE0h+reCJdhopGiTqWGDEE/broc5UIWoCaBhH/yXsfkrpM32wHjk0EXGYgQgI7LO6tKy07gUQZZ2W1q9gx9DZ0SVY1J0JEgUO2MhGNrmiS3btMg2U7sm4iNtSqDY2rnkbA/7Ll7Mwk6EI0zx72njBumb7yAuUwRtLu8tyVmfrG3xKrs8A+JxmuH1ee/K7w3ju2LLoAskuFPpZLBiXUsgezegwZph++ng1bZl47FH7lyOarwImXyNojE3I5atUMXK8uHWAU/cqIXllTWhLNLsYfz+yplICz4gn7P0RIhwG06R+jJckMjdkxrjNo5PjZ2S6g+5+4oMFO2FTnf1TRw5ug6N62eZoRk+zRqnGI0asTsG9SUmgs740ohnt6N1qpXMN330kGATdJWFdewl3jUJJTzPaPc3YfQCGMhtRYZpBhTJ3MvHtjI9peYCydRkKYSyO4yjwkkb2UIy9HUi0ckfJ4B1sTIFv/Cf0U/fogjmycT9m4IjiYKKurwMeA9PxeRjQoE4/BNAOQtcJNTxhdnoTC0wXvRY0nDCoT3so17mDZv16qx70365xs30wkv2vLgcXBxVTWjEdM92eXBW0l09fjDM+sBOfNzuesaNTG8eEoe52GNAjWzcOdCPct0wEPX/49tM4StOoNr/X840eY10fJtGE/amkHmpsBvfcp2vhsWiLTyW2cRyBt2nZUpk7Uy7DMmnOmiS/ZhcBwSuWXamHjE1Q1znaaCZSGB2BK1VZc3uWSKDeZo51Hdlvxbb++f3H1ujz4qC1viLQnQtEjkkygvotAE+4Cm4c8mpFp8QN83bwtZEXR9A3bVuwYSc5VxBZnb40cO9XwS549M3LC33ZnE7w7bGyOJ+NFE/heG8+N0a+J4yPoCgY0Mix47zdiyc4ZkwGHyfoiqULsmGzGrBZL0Av87mg3wbfCuozpGibiYbnQAFzyd1bKLLzJ17s9lB3f1guyZ1EbIt/4QZdxT9KXhEV6kjC5qtl8wxLGAuAyXceE41fxVcaT4DYOZrtVxAjf23O4pAwT8tiBzN2BheTS3v4XcXzImVRVdTzpyJXe+C+vPq+eTbXr888pBj2oYCSb5VOGJIB6YJe0VXOfpNAldN5SwRXVjGDqUJQGuvebxoWcAyxegyFE/BpoCHTBwD16lR4BvYnp/8AM8Po5Q==

Steps to reproduce

1、使用 template 标签

2、保证template生成sfc_render函数里有h函数的执行,比如:计算属性读取h函数执行的结果,一个方法的执行返回h函数执行的结果

3、使用v-show进行显示隐藏的切换时即会看到报错

What is expected?

预期是vnode生成正常,不报错

What is actually happening?

1、使用template模式在执行其生成的sfc_render函数时,会先通过openBlock方法分开层级关系 2、而openBlock之后,如果有某属性值的读取调用了h函数,也就会调用createVNode => createBaseVNode 3、createBaseVNode方法会往currentBlock里push对应创建的vnode 4、所以就会导致dynamicChildren的数量可能不一致(因为执行一次后结果会有缓存,但如果是计算属性数量也不一定不一致) 5、到后续patch时,就可能会有奇怪的结果,比如只更新了前面一部分,或者读取到节点的el不存在parentElement导致insertBefore error

System Info

No response

Any additional comments?

目前找到能用的一个方法是在使用h函数的前后,使用setBlockTracking来避免往currentBlock里push,但是不确定这是不是一个好办法

其它能想到的可能的处理方式是: 1、在h函数添加一个isBlockNode的参数,透传true来避免往currentBlock里push 2、或者使用setBlockTracking包一层h函数,类似slot那样,对外提供一个新方法?

avatar
May 2nd 2023

duplicate of https://github.com/vuejs/core/issues/6913 as a workaround

    const icon = computed(() => {
      setBlockTracking(-1)
      const res = h(BackTopIcon)
      setBlockTracking(1)
      return res
    });
avatar
May 2nd 2023

duplicate of #6913 as a workaround

    const icon = computed(() => {
      setBlockTracking(-1)
      const res = h(BackTopIcon)
      setBlockTracking(1)
      return res
    });

好的,感谢确认!

这里为了保持向前兼容,setBlockTracking方法就必须保持public了,直到有新的api来处理这种情况

想问下这块有没有计划进行优化,以提供更简便的实现方式?

avatar
May 2nd 2023

@nined9 see #8213

Niubility!