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

Suspense+KeepAlive+AsyncComponent+v-if causes the Uncaught (in promise): Cannot read properties of null (reading 'parentNode') #6463

Closed
mefcorvi opened this issue Aug 13, 2022 · 16 comments · Fixed by #7290

Comments

@mefcorvi
Copy link
Contributor

mefcorvi commented Aug 13, 2022

Vue version

3.2.37

Link to minimal reproduction

https://play.vuejs.org/#eNqNVMtu2zAQ/JWFLpGBWEyRnlLZiBvk0BZtg9pHXRRpZTGVSIKk/EDgf++SlGzVToCcLHJfM7NDv0YLpZJNh9FdlFpsVZNbnGcCIF12RqEw4UTnkm/6Tzr8QFSLhm+GqL98aNXC7EUBmymvZlnEzbKWW5FFwE6V7Lw0ZUPnlI1mpmwEJzWF5sqCQdspn8tbJbWF19CjxIoL9MMfJEUECnsdQlL8lJ2wWPZnjZX/OkClZQtXxP3qy6gjkegjCXO9nDguwaUUUhifEWjO3pwbhznxBGZzELiFJ+rGDcaxRuMve9Dg6Kx4i7KzcUinjJjaT67h083NzcTjIqgT9+tOJxC9toSBCMVWdzjEj4T7nv20i1lHFIwBr1z82NRKcB3B1igAN6j3tuZiDVveNPCM4EiPqqWGzqDf/xw4ocO8BFmdDHHcfj8g2eQNtZ9BlTcGB5aedOB8cD8pC1ufR9dRWM60zVXyYqQgt3r45DEfMFl0NxDKItqYO2dRba0yd4wVpaCyEsl1OhFomVAtu6c0pkkpUmVayvb+NrlNPpMZjR1fJ2ja6bOWW4OammRR7yM/htElyTPVKErUqD869qxsPPosdDHey5OJA4ky2PPy7Z7e6qrmBizu6O3UsmtKciS1d0ukaVSxxzI8vVAyenU0wBoyW8XXZ5oXNJc3qH8ry8mM/2mfN43cfvd3zkJHsYoai79v3L+YXRDtibzvqI8Etrleow3hx+UvIjEKtrLsmn7P7wT/oJFN5zCGtK+dKAn2KM+j/eYtRP5emcedpb+fgZQD6uX2+X7hTvL3qJ/g0jqPazr8AxfWwHU=

Steps to reproduce

The reproduction link demonstrates the issue with no action required.

  1. Put an async component inside the <KeepAlive>.
  2. Assume we have <Suspense> somewhere up in the tree.
  3. Add conditional rendering to that async component using v-if. The initial condition should be set to true.
  4. Change that condition to the false before the async component is fully loaded.

What is expected?

The async component is loaded but not rendered.
No errors in the logs.

What is actually happening?

[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/core 
  at <KeepAlive> 
  at <Repl>

vue.runtime.esm-browser.js:9243 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'parentNode')
    at parentNode (vue.runtime.esm-browser.js:9243:30)
    at ReactiveEffect.componentUpdateFn [as fn] (vue.runtime.esm-browser.js:7062:17)
    at ReactiveEffect.run (vue.runtime.esm-browser.js:531:25)
    at instance.update (vue.runtime.esm-browser.js:7094:56)
    at updateComponent (vue.runtime.esm-browser.js:6919:26)
    at processComponent (vue.runtime.esm-browser.js:6852:13)
    at patch (vue.runtime.esm-browser.js:6450:21)
    at patchBlockChildren (vue.runtime.esm-browser.js:6756:13)
    at patchElement (vue.runtime.esm-browser.js:6664:13)
    at processElement (vue.runtime.esm-browser.js:6530:13)

Notes

Another issue here is Uncaught (in promise): suspense.resolve() is called without a pending branch. error that is thrown if there is no KeepAlive component in the tree. This error is caused by double calling the "resolve" method of the same suspense object when an async component is unmounted before the resolution of the suspense.

// A component with async dep inside a pending suspense is unmounted before
// its async dep resolves. This should remove the dep from the suspense, and
// cause the suspense to resolve immediately if that was the last dep.
if (
__FEATURE_SUSPENSE__ &&
parentSuspense &&
parentSuspense.pendingBranch &&
!parentSuspense.isUnmounted &&
instance.asyncDep &&
!instance.asyncResolved &&
instance.suspenseId === parentSuspense.pendingId
) {
parentSuspense.deps--
if (parentSuspense.deps === 0) {
parentSuspense.resolve()
}
}

if (suspense.deps <= 0) {
suspense.resolve()
} else if (isInFallback) {

You can put an async component into a wrapper component (it can just render the default slot). In that case neither KeepAlive or Suspense is rerendered. Although this makes KeepAlive useless.

https://play.vuejs.org/#eNqNVE1P4zAQ/Suj7GFTicZ0uye2rWARh/1GC8dcQjIhhsS2bKcFof73HdtJmhSQ9pSM5/O9efZLdKFUsm0xOotWFhtVZxY3qQBY3bRGoTDBIrvg2+6XjB+I6qLm297rDy8btRjZ4eTCPIsctnNertOIm5tK7kQaARsnsknmih1XX7FD82FK+FBmdX2X5Y9D5k+ZFVzcJ0nS500hsRGmiW9lcs2VBYO2VT6WN0pqCy+hUIElF+ihXEryCBT2JLik+CVbYbHobI2l/9tDqWUDH4nbj19GFQlq50mYq+XIPw5YTCIWfYgLyqUwPibwun5ztDiMEs9gvQGBO7imctxgHGs0/rDDBQ7xLW9QtjYO4RQRU/nZCSxOT09nfjJCM3NfZx2G6JZJMxDm2OoWe//ASVez6/aq1zAFY8BL5x+KWgmuItgKBeAW9bOtaLWw43UNdwgO9ChbamgNesFtgNN0mBUgy4MCB410DZJtVlP5NZCIDPYoPeiAee8+KxaEsYlOorCeeZOp5MFIQRfGj0+i9g6TRmc9oDSijTk7jSprlTljLC8EpRVIqtaJQMuEatg5hTFNTBEr80I258vkU7L8TGo3dnyeoGnmd1ruDGqqkkad1nwfRofEz1yjKFCj/t++R2mT3ke+V/09QanYEy29hl8/IIc7e1txAxaf6IJVsq0L0iSVd2ukbpTxjEW4nyFldDWpgTUkt5LfH7GeU19eo/6jLCc5Ttind0HuvvszJ6KBrbzC/PGN8wfzFFi7JvU76COGbabv0Qb31c1vAjFyNrJo627T7zj/opF162YMYV9bUdDYozg/7TcvIlL4rbl6svRG9aDcoJ5uH+837ih/D/ph3GWyPFqTf0ime9Ked1NL615kssbc7/8Bq7z4Vg==

@jiangmaniu
Copy link

Same error, what's the progress?

@wellfrog16
Copy link

wellfrog16 commented Oct 3, 2022

在vuepress 2.x下面有同样的问题
image

@DrJume
Copy link
Contributor

DrJume commented Feb 17, 2023

The reproduction throws the same error on vue v3.2.36

@DrJume
Copy link
Contributor

DrJume commented Feb 17, 2023

I had the same issue inside a Nuxt v3.2.2 app, probably caused by a suspense boundary with async components.

In the following line prevTree.el is null, when the error is thrown (null.parentNode). Sometimes it is "", which does not throw, as "".parentNode gives undefined, which does not cause any problems.

hostParentNode(prevTree.el!)!,

I think it is some kind of race condition, where the prevTree.el is not available, because of the async component being removed / not being ready.

@joel-wenzel
Copy link

joel-wenzel commented Feb 23, 2023

Same issue for me with Nuxt 3.1.1.

Changing line 35 of @vue/runtime-dom runtime-dom.esm-bundler.js to
parentNode: node => node ? node.parentNode : null, seems to fix the issue though I am not sure what downstream effects this could have.

@aKzenT
Copy link

aKzenT commented Apr 5, 2023

Same issue here.

@theguriev
Copy link

Same issue on my side :(

@Ingramz
Copy link

Ingramz commented Jul 3, 2023

Here is another reproduction that does not seemingly make use of KeepAlive but still triggers this error.
https://stackblitz.com/edit/github-8d62xc
To trigger, click on one of the links.

The code is nonsensical from the practical aspect as it hides the element when it loads the fallback component. Despite this, it is hard for me to assess whether the code itself is valid and belongs to the same type of issue.

@ilyaDegtyarenko
Copy link

Nuxt 3.7.3

Detailed reproduction:
https://stackblitz.com/edit/nuxt-starter-btlcfb?file=pages%2Fwaiting.vue

@alexovn
Copy link

alexovn commented Sep 22, 2023

I have same issue, so only this answer helped me. Hope it will be fixed soon

Same issue for me with Nuxt 3.1.1.

Changing line 35 of @vue/runtime-dom runtime-dom.esm-bundler.js to parentNode: node => node ? node.parentNode : null, seems to fix the issue though I am not sure what downstream effects this could have.

@plcdnl
Copy link

plcdnl commented Oct 20, 2023

Same issue for me with Nuxt 3.1.1.

Changing line 35 of @vue/runtime-dom runtime-dom.esm-bundler.js to parentNode: node => node ? node.parentNode : null, seems to fix the issue though I am not sure what downstream effects this could have.

Had the same problem in nuxt 3.8.0. Finally solved by patching in this way! Thank you, i hope can be helpful for the fix

@TomasSestak
Copy link

this is serious issue - is it on the roadmap?

@edison1105
Copy link
Member

edison1105 commented Oct 29, 2023

The problem is here:

if (isSameVNodeType(newBranch, pendingBranch)) {
// same root type but content may have changed.
patch(
pendingBranch,
newBranch,
suspense.hiddenContainer,
null,
parentComponent,
suspense,
isSVG,
slotScopeIds,
optimized
)
if (suspense.deps <= 0) {
suspense.resolve()
} else if (isInFallback) {
patch(
activeBranch,
newFallback,
container,
anchor,
parentComponent,
null, // fallback tree will not have suspense context
isSVG,
slotScopeIds,
optimized
)
setActiveBranch(suspense, newFallback)
}
} else {
// toggled before pending tree is resolved
suspense.pendingId++
if (isHydrating) {
// if toggled before hydration is finished, the current DOM tree is

When the component is toggled before the pending tree is resolved, patching should not be performed. Instead, the logic under the "else" statement should be executed. based on the current code, the component should be used as the root node of Suspense and should not be wrapped by any other elements.

The correct nesting order should be as follows:

<KeepAlive>
  <Suspense>
    <!-- main content -->
    <component :is="Component"></component>

    <!-- loading state -->
    <template #fallback>
      Loading...
    </template>
  </Suspense>
</KeepAlive>

see https://vuejs.org/guide/built-ins/suspense.html#combining-with-other-components

or add a key see

<Suspense>
  <div :key="+isShown">
    <KeepAlive>
      <CmpAsync v-if="isShown" />
    </KeepAlive>
  </div>
</Suspense>

this will be fixed via #7290

@edison1105
Copy link
Member

duplicate of #6095

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

Successfully merging a pull request may close this issue.