Subscribe on changes!

vnode 生命周期事件使用时候出现内存溢出

avatar
Jan 7th 2022

Version

3.2.26

Reproduction link

sfc.vuejs.org/

Steps to reproduce

将vnode生命周期事件 @vnodeMounted 改为 onVnodeMounted,则会出现内存溢出

What is expected?

事件传递,或者正常触发生命周期事件

What is actually happening?

Uncaught RangeError: Maximum call stack size exceeded
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8082)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)
    at callWithAsyncErrorHandling (runtime-dom.esm-browser.js:8094)

根据目前对文档的熟悉,我发现所有的@event定义的事件都会被转为onEvent进行事件传递,并且,直接传递onEvent和@event表现是一致的,都能够触发原生事件以及被注册为Vue自定义事件。但是当我将vnode生命周期事件进行更改后则出现了内存溢出

avatar
Jan 7th 2022

直接传递onEvent和@event表现是一致的,都能够触发原生事件以及被注册为Vue自定义事件

不是这样的,请使用@vnodeMounted,直接使用onVnodeMounted作为prop名字会命中这个特殊逻辑从而导致错误

// onVnodeMounted
if (
  !isAsyncWrapperVNode &&
  (vnodeHook = props && props.onVnodeMounted)
) {
  const scopedInitialVNode = initialVNode
  queuePostRenderEffect(
    () => invokeVNodeHook(vnodeHook!, parent, scopedInitialVNode),
    parentSuspense
  )
}
avatar
Jan 7th 2022

直接使用onVnodeMounted作为prop名字会命中这个特殊逻辑从而导致错误

是的,这里逻辑错误确实是因为这里作为prop名字(测试的时候忘记了:冒号),命中了这个特殊逻辑。 不过我传递onVnodeMounted确实得到的结果和@vnode-mounted是一致的。

<template>
    <!-- 这两者结果一致 -->
     <custom-component :onVnodeMounted="onVnodeMounted"></custom-component>
     <custom-component @vnode-mounted="onVnodeMounted"></custom-component>
<template>

请问这两者区别在哪儿呢?我没有找到相应的代码逻辑。但是确实当onVnodeMounted为非函数时,:onVnodeMounted="onVnodeMounted"报内存溢出,而@vnode-mounted="onVnodeMounted"不会报错,只是被忽略了

avatar
Jan 10th 2022

直接使用onVnodeMounted作为prop名字会命中这个特殊逻辑从而导致错误

是的,这里逻辑错误确实是因为这里作为prop名字(测试的时候忘记了:冒号),命中了这个特殊逻辑。 不过我传递onVnodeMounted确实得到的结果和@vnode-mounted是一致的。

<template>
    <!-- 这两者结果一致 -->
     <custom-component :onVnodeMounted="onVnodeMounted"></custom-component>
     <custom-component @vnode-mounted="onVnodeMounted"></custom-component>
<template>

请问这两者区别在哪儿呢?我没有找到相应的代码逻辑。但是确实当onVnodeMounted为非函数时,:onVnodeMounted="onVnodeMounted"报内存溢出,而@vnode-mounted="onVnodeMounted"不会报错,只是被忽略了

这两种方式的底层的指令不同 @vnode-mounted="onVnodeMounted" 这种是 v-on:vnodeMounted="onChildMounted"的缩写 :onVnodeMounted="onVnodeMounted" 是 v-bind:onVnodeMounted="onVnodeMounted"的缩写 而v-bind, v-on是两种指令,一种是绑定数据,一种是监听事件。 https://v3.cn.vuejs.org/guide/template-syntax.html#v-bind-%E7%BC%A9%E5%86%99 https://v3.cn.vuejs.org/guide/events.html#%E7%9B%91%E5%90%AC%E4%BA%8B%E4%BB%B6 https://v3.cn.vuejs.org/guide/component-custom-events.html

avatar
Jan 16th 2022

@vnode-mountedonVnodeMounted 实质上是等价的。原 issue 的问题在于没有用 : 导致传递的其实是一个字符串。错误也不是内存溢出而是爆栈。