vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.47k stars 8.3k forks source link

if computed returns a object {} and await in setup, triggering the watch callback and causing an infinite loop. #11078

Open green-mike opened 4 months ago

green-mike commented 4 months ago

Vue version

3.4.27

Link to minimal reproduction

https://stackblitz.com/edit/nuxt-issues-27454?file=src%2FApp.vue&terminal=dev

Steps to reproduce

What is expected?

if the computed variable's value changes, trigger the watch context.

What is actually happening?

A recursion occurs and show message 'UnhandledPromiseRejection' in node.

[UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Maximum recursive updates exceeded. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.".] {
  code: 'ERR_UNHANDLED_REJECTION'
}

System Info

System:
    OS: macOS 14.4.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 121.70 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.9.0 - ~/.nvm/versions/node/v20.9.0/bin/node
    npm: 10.1.0 - ~/.nvm/versions/node/v20.9.0/bin/npm
    pnpm: 9.1.2 - /opt/homebrew/bin/pnpm
  Browsers:
    Brave Browser: 124.1.65.126
    Chrome: 125.0.6422.142
    Edge: 125.0.2535.85
    Safari: 17.4.1

Any additional comments?

This code causes recursive updates because the computed property routeVariables returns a new object {} each time it is accessed. When mockAsync is awaited, the watch callback is triggered, leading to an infinite loop. Reporting this bug because the documentation does not indicate that computed values cannot be used in the setup or watch immediate contexts. Moreover, no error messages appear in the client side. I suspect Vue-SSR might be causing this issue. My actual use case is more complex, requiring URL parsing, then calling an API, and setting the return value as the initial value. Therefore, it took considerable time to narrow down and reproduce the issue. During this period, I found that using the oldValue of a computed property to avoid object updates or using newValue in watch can mitigate the problem. However, since there are no errors in the client side and no hints in the documentation, this is still a valuable case to report.

yangliguo7 commented 4 months ago

if u use async setup. u should use boundary

https://play.vuejs.org/#eNqNU01v2zAM/SuCLnaBwEG3nTrHQzfksB22Yi12EjBoNuOqlSVDH06GwP99pJxkztYWzSG2yPeox0d6z6/7vhgi8Cte+tqpPjAtTbsSPHjBmYcQ+0oY1fXWBfbJdj3bONsxwYslnYgruDDlcmIjFg8Bul7LAHhirLyNvgfjoSqJUZWJiI9TnOgzCl/g5bU1G9UWD94a1LanQoLXSFQa3Lc+KGtQ4BVLGcpJre32S4oFF2FxjNf3UD8+EX/wO4oJfuPAgxuwjVMuSNdCmNLr26+ww/dTsrNN1Ih+IfkdvNWRNE6wj9E0KHuGS2o/J1eVae/8ehfQimNTJJSQY8ILjiaTZ8+1/lfu2+Jd4gkzoovHAb1uuHtG9sYAzYJtZajv2TjNOsMS2XthcCQ+MGcR8kM6JX9p8Gx1YuX5BVtVkyqHpZ1h+xFp4wX+CSO3UgXW2frx2v82dT5F00V5opzVTY3PCjK8xqCpUGjb5tk5OFv8wy4GqSPQDUcPD0VU10GjcM1my4BmHRSSLraJpiaL51LPmjKwZTfoi/KQ57g7Vg8wF4q23qkOUNDcEfodwHlGpbNJHglklwep9EA5L31MjRqqtXPWfSiX9P7/t/NzAEebhFPHdSjeXPLxD8FCTlI=

green-mike commented 4 months ago

Hi, I use boundary in the Vue SFC Playground too, but it still shows 'SSR Error'. I also put it on StackBlitz, and it has the same problem.

yangliguo7 commented 4 months ago

Vue SFC Playground

u use ssr option

image

green-mike commented 4 months ago

Yes, I noticed that this issue only occurs in the SSR environment. The same code does not produce errors in the browser, so I consider it a bug.

edison1105 commented 3 hours ago

The issue can no longer be reproduced using the latest version of Vue. see https://stackblitz.com/edit/nuxt-issues-27454-6qv6vm?file=package.json