Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Не обновляется обработчик события на DOM узле при ререндере #1322

Closed
shining-mind opened this issue Jul 5, 2024 · 2 comments
Labels

Comments

@shining-mind
Copy link
Contributor

shining-mind commented Jul 5, 2024

Vue может переиспользовать существующие DOM узлы при ререндере. Если на DOM узле, уже есть обработчик (el._vei), то Vue обновит его проставив ссылку на новую функцию, при этом addEventListener использоваться не будет.

В некоторых случаях vnode узлы генерируются с флагом 32 (HYDRATE_EVENTS), в этом случае Vue не добавит vnode как динамический:

    // данный код выполняется внутри createBaseVNode
    // track vnode for block tree
    if (isBlockTreeEnabled > 0 &&
        // avoid a block node from tracking itself
        !isBlockNode &&
        // has current parent block
        currentBlock &&
        // presence of a patch flag indicates this node needs patching on updates.
        // component nodes also should always be patched, because even if the
        // component doesn't need to update, it needs to persist the instance on to
        // the next vnode so that it can be properly unmounted later.
        (vnode.patchFlag > 0 || shapeFlag & 6 /* ShapeFlags.COMPONENT */) &&
        // the EVENTS flag is only for hydration and if it is the only flag, the
        // vnode should not be considered dynamic due to handler caching.
        vnode.patchFlag !== 32 /* PatchFlags.HYDRATE_EVENTS */) {
        currentBlock.push(vnode);
    }

Мы со своей стороны для vnode задаем проп data-has-v-on-directives, и в patchFlag дописываем 8 (PROPS), однако, так как при создании vnode в createBaseVNode в currentBlock узел не добавляется, то узел все равно будет считаться не динамическим.

Пример

Исходный код

< .&__toggler @click.capture.stop = (e) => actionGuard.protectDomEvent(e, onInitialAddClick.bind(self))

Скомпилированный узел

_createElementVNode.call(_ctx, "div", {
    class: "b-ufo-count-badge__toggler",
    onClickCapture: _cache[0] || (_cache[0] = _withModifiers.call(_ctx, (e) => _ctx.actionGuard.protectDomEvent(e, _ctx.onInitialAddClick.bind(_ctx.self)), ["stop"])),
    "data-cached-class-component-id": "true",
    "data-cached-class-provided-classes-styles": "toggler",
    "data-has-v-on-directives": ""
}, [
    // ...  дочерние узлы 
], 32 /* HYDRATE_EVENTS */ )

Если же @click.capture.stop заменить на @click.stop или @click, то патч флаги не будут заданы вообще и блок все равно будет не динамическим.

@shining-mind
Copy link
Contributor Author

shining-mind commented Jul 5, 2024

Потенциально проблема очень серьезная, так как если изначально у узла нет патч флагов и это не компонент, то такой узел отслеживаться не будет (при условии, что он внутри блока).

@shining-mind
Copy link
Contributor Author

Fixed in #1323

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant