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

v-memo v-for with inline array iteration error "can't access property "el", oldVNode is undefined" #4253

Closed
lidlanca opened this issue Aug 4, 2021 · 6 comments · Fixed by #4270
Labels
❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. 🐞 bug Something isn't working

Comments

@lidlanca
Copy link
Contributor

lidlanca commented Aug 4, 2021

Version

3.2.0-beta.7

Reproduction link

sfc playground

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

  1. 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
@posva posva added 🐞 bug Something isn't working ❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. labels Aug 4, 2021
@sqal
Copy link
Contributor

sqal commented Aug 5, 2021

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

@lidlanca
Copy link
Contributor Author

lidlanca commented Aug 5, 2021

are you sure its not the error you get on the 4th click?

@sqal
Copy link
Contributor

sqal commented Aug 5, 2021

ahh yes, it shows up on 4th click, nevermind then

@edison1105
Copy link
Member

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 */))
}

@lidlanca
Copy link
Contributor Author

lidlanca commented Aug 6, 2021

it will be interesting to see if this also related to this root cause #4262

@edison1105
Copy link
Member

edison1105 commented Aug 6, 2021

@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)
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
❗ p4-important Priority 4: this fixes bugs that violate documented behavior, or significantly improves perf. 🐞 bug Something isn't working
Projects
None yet
4 participants