v-memo v-for with inline array iteration error "can't access property "el", oldVNode is undefined"
Version
3.2.0-beta.7
Reproduction link
this is inline example that does not work an raise the error
// [1,2,3] inline array
v-for="v,k in [1,2,3]"
the following will work as expected ( when arr = [1,2,3] )
v-for="v,k in arr"
Steps to reproduce
open sfc
- click inc button 3 times, when v-memo trigger a change the error will show.
What is expected?
no error
What is actually happening?
Uncaught (in promise): can't access property "el", oldVNode is undefined
I noticed another bug in your example. If you declare an array using const instead of let/var then following error occurs
Uncaught (in promise): Cannot read property 'emitsOptions' of null
the root cause is:
return (_ctx, _cache) => {
return (_openBlock(), _createElementBlock(_Fragment, null, [
_createElementVNode("button", {
onClick: _cache[0] || (_cache[0] = $event => (count.value++))
}, " inc " + _toDisplayString(count.value), 1 /* TEXT */),
(_openBlock(), _createElementBlock(_Fragment, null, _renderList([1,2,3], (id, index, ___, _cached) => {
const _memo = ([count.value < 3 ? true : count.value])
+ we will lose the `dynamicChidren` (the `currentBlock` is empty) because return the cached vnode here.
if (_cached && _cached.key === id && _isMemoSame(_cached.memo, _memo)) return _cached
const _item = _createVNode(__import_1__.default, {
count: count.value,
index: index,
key: id
}, null, 8 /* PROPS */, ["count", "index"])
_item.memo = _memo
return _item
}, _cache, 1), 64 /* STABLE_FRAGMENT */))
], 64 /* STABLE_FRAGMENT */))
}
it will be interesting to see if this also related to this root cause https://github.com/vuejs/vue-next/issues/4262
@lidlanca
withMemo
works fine because it catches the block tree.
see :
export function withMemo(
memo: any[],
render: () => VNode<any, any>,
cache: any[],
index: number
) {
const cached = cache[index] as VNode | undefined
if (cached && isMemoSame(cached.memo!, memo)) {
// make sure to let parent block track it when returning cached
if (isBlockTreeEnabled > 0 && currentBlock) {
currentBlock.push(cached)
}
return cached
}
const ret = render()
ret.memo = memo
return (cache[index] = ret)
}