3.0.4
https://codesandbox.io/s/misty-tree-xzmh1?file=/src/main.js
Open the link, check the console
The template ref should be <div>hello</div>
The template ref is <div>foo</div>
Very strange, I added a breakpoint and it worked.

Is this because the <div> is being reused across renderings and the console logging shows the current content of that <div>, not the content it had when it was logged? The content of that <div> gets updated when it re-renders. You'd need to give it a key for the diffing to pair up the correct nodes.
Using console.log(refDom.value.innerHTML); seems to give the correct value.
Yep. Would say this is expected behavior.
I think this is a bug, if you replace patchKeyedChildren with patchUnkeyedChildren, then everything will work fine.
Check this link, the click event will be bound to div(foo): https://codesandbox.io/s/throbbing-snowflake-vpm1x, but when mounted, patch has not been performed yet, let alone reuse, the div(foo) doesn't exist yet, right?
In this reproduction, if you remove the refVal.value && h('span', 'bar') sentence, it will also work correctly, I tracked this issue and its update process is as follows:
The pre-vnode:
[
prev-comment1,
prev-div(hello),
prev-comment2
]
The next-vnode:
[
next-div(foo),
next-div(hello),
next-div(bar)
]
prev-comment1prev-div(hello) ---> next-div(foo)comment2next div(bar)next div(hello)But I don鈥檛 know what caused the problem, it's weird, just like @edison1105 said.
Please reopen this issue, wait @yyx990803 to check it.
I can't follow.
The div will be re-used as it doesn't have a key. That's expected behavior (or did I miss an optization in Vue 3? Totally possible!).
Since it's being re-used, the logged element will first contain 'hello', but the component will immediately update due to the changed ref value to true, so it will only show 'hello' for a millisecond, not enough to catch it with the eyes.
So in that update, the element will be patched to now contain 'foo', and the logged element, which is still the same same element, will show as 'foo'.
So in short I don't understand what the bug is supposed to be.
I think I get it now. Thanks for explaining.
Reopening.
The immediate reason is that setRef is async, so that the refDom.value has a preValue on the first frame.
https://github.com/vuejs/vue-next/blob/07559e5dd7e392c415d098f75ab4dee03065302e/packages/runtime-core/src/renderer.ts#L344-L358
You can change the onMounted callback like code blow to verify it in reproduction link https://codesandbox.io/s/throbbing-snowflake-vpm1x provided by @qq397023775
onMounted(() => {
refDom.value.addEventListener("click", () => {
console.log("what????");
});
console.log(refDom.value)
setTimeout(() => {
console.log(refDom.value)
})
refVal.value = true;
});
And then you can find that the refDom.value is div(foo) on the first frame and div(hello) on the next frame.
But the root cause i think is incorrect element reusing when patch , i will create a PR to take up.
By the way, as a workround you can wrap the dom handle into nextTick.
But the root cause i think is incorrect element reusing when patch
@luwuer
This problem has nothing to do with patch, please note that we have already had the issue in the onMounted hook, and no patch has been performed yet.
Hook mounted is trigger after patch.
Hook mounted is trigger after patch.
Completely wrong, the patch here refers to the update triggered after changing the reactive data. the mounted is always before the updated.
Completely wrong, the patch here refers to the update triggered after changing the reactive data. the
mountedis always before theupdated.
Its ok mounted before update.
But there one thing i didnt make clear that the refDom.value is correct when mounted (alreay patch), and go wrong when
patch before updated hook(dom children were changed). To verify it you can remove code refVal.value = true.
So i said:
i think is incorrect element reusing when patch

Your solution is not correct. There is no problem in reusing nodes, because pre-div(hello) and next-div(foo) should be reusable, because their type(div) and key(undefined) are the same, which has nothing to do with ref dom.
Your solution is not correct. There is no problem in reusing nodes, because pre-div(hello) and next-div(foo) should be reusable, because their type(div) and key(undefined) are the same, which has nothing to do with ref dom.
yep, consensus.
But if resuing when there has ref will lead to this issue, and the refDom.value will be changed nextTick.
Also锛宺esuing without ref assertion will change the uid of VNode of div(hello) . This seem not to be a principle of reuse.
The problem you see comes from logging in the console the HTML node, but the variable contains the right HTMLElement all the time: the div with the hello text. At some point, the node gets reused (as mentioned in a comment above) but the ref ends up pointing to the correct node. If you manage to reproduce it where the ref points to the wrong element, open a new issue with a breaking example.
Looking at https://vue-next-template-explorer.netlify.app/ to compare the output render function with the one you manually wrote could also make it easier to expose the bug
Just calling @yyx990803 , I believe he can give me the answer.
The problem you see comes from logging in the console the HTML node, but the variable contains the right HTMLElement all the time: the
divwith thehellotext. At some point, the node gets reused (as mentioned in a comment above) but the ref ends up pointing to the correct node.
Ref pointing to wrong HTMLElement at one tick, actually. @posva
onMounted(() => {
refDom.value.addEventListener("click", () => {
console.log("what????");
});
// --- notice console log ---
console.log(refDom.value)
setTimeout(() => {
console.log(refDom.value)
})
// --- notice console log ---
refVal.value = true;
});

This example is in a comment above.
Most helpful comment
Is this because the
<div>is being reused across renderings and the console logging shows the current content of that<div>, not the content it had when it was logged? The content of that<div>gets updated when it re-renders. You'd need to give it akeyfor the diffing to pair up the correct nodes.Using
console.log(refDom.value.innerHTML);seems to give the correct value.