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

Maximum recursive updates exceeded in component in 3.4.27 #11121

Closed
wanghanzhen opened this issue Jun 13, 2024 · 10 comments · Fixed by #11135
Closed

Maximum recursive updates exceeded in component in 3.4.27 #11121

wanghanzhen opened this issue Jun 13, 2024 · 10 comments · Fixed by #11135

Comments

@wanghanzhen
Copy link

wanghanzhen commented Jun 13, 2024

Vue version

3.4.27

Link to minimal reproduction

https://play.vuejs.org/#eNp9UttKw0AQ/ZVhX2yxpGoFoaYFLRX0QYv6uCBpOqmpye6yl1gJ+XdnN70Jtm/LucycmZ2a3SkVVQ7ZkMUm1bmyYNA6NeYiL5XUFmpIZamcxUUPNGbQQKZlCWdkOuOCi1QKYyGTEkae71x0b/fwPNEEbwt0Ol0YjaHmArwhqpLCIZyP4JIsQG7rtNgzBDZtsbjfZqNUscVSFYlFegPEi7wa13Vofx66NU3c96A3HUhZj1lDmbJ8Ga2MFDRviMGZD5cXqF+UzSkzZ8M2oOeSopDfTwGz2mFvi6efmH79g6/M2mOczTQa1BVytuNsopdoW3r69oxreu/IUi5cQeoT5CsaWTifsZXdO7Gg2Ae6kPYx/Foulu9murYozHYoH9Qrm6DnjP5vcmL0fdxBNAg++g3a4gw1rY92SBvcXcjxu1BBPpFO2L/3gevgzZxIffON8CFJrdQ/HZGU2G3DtHXkfEX+TTrPDkOxoAsDNaEqHDY8cl9Uyl9WuImPiuTUnoYZRNfR1Q1rfgG5gQZ0

Steps to reproduce

Open the link and see the maximum recursion error

What is expected?

No maximum recursion error

What is actually happening?

Maximum recursion error

System Info

System:
    OS: macOS 14.4.1
    CPU: (16) x64 Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz
    Memory: 50.06 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.17.1 - ~/.nvm/versions/node/v18.17.1/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v18.17.1/bin/yarn
    npm: 9.6.7 - ~/.nvm/versions/node/v18.17.1/bin/npm
    pnpm: 8.7.6 - ~/.nvm/versions/node/v18.17.1/bin/pnpm
    bun: 1.0.25 - ~/.bun/bin/bun
  Browsers:
    Chrome: 125.0.6422.142
    Safari: 17.4.1

Any additional comments?

This issue is similar to #10214 which was fixed by #10232, but I don't think it has been completely resolved.
Take a look at the reproduction link and "Maximum recursion error" still happened.

I also modified a test case to get the same error.
image

Using two same computed in render could cause the same error.
image

@edison1105
Copy link
Member

edison1105 commented Jun 13, 2024

It works fine with v3.5.0-alpha.2

@wanghanzhen
Copy link
Author

It works fine with v3.5.0-alpha.2

Could it be fixed in 3.4? I just upgraded to 3.4, Alpha version is unstable.

By the way,do you know which mr or commit fixed it?

@edison1105
Copy link
Member

@wanghanzhen this one #10397

@LinusBorg
Copy link
Member

Sidenote: Mutating external state from within a computed is an anti-pattern. Should still not end in recursive loop, but still ...

@wanghanzhen
Copy link
Author

@wanghanzhen this one #10397

seems such a big change😨. Is there a temporary and simple solution? @johnsoncodehk Looking forward to your advice🙏

@johnsoncodehk
Copy link
Member

I am unable to focus on this for now, @Doctor-wu are you interested in taking a look at this?

@Doctor-wu
Copy link
Member

I am unable to focus on this for now, @Doctor-wu are you interested in taking a look at this?

Sure, I'll take a look at this 👀

@johnsoncodehk
Copy link
Member

johnsoncodehk commented Jun 14, 2024

The reproducible case can be simplified to the following code (without using computed), I think causing infinite recursion is expected behavior.

<script setup>
import { ref } from 'vue'

const foo = ref(0);
const bar = () => {
  foo.value += 1;
  return foo.value;
};
</script>

<template>
  <div>{{ foo + bar() }}</div>
</template>

If you must write such logic, you should use pauseTracking to avoid tracking dependencies before side-effect code.

<script setup>
import { ref, computed } from 'vue'
import { pauseTracking, resetTracking } from '@vue/reactivity'

const foo = ref(0);
const bar = computed(() => {
  foo.value += 1;
  return foo.value;
});
const baz = computed(() => {
  pauseTracking();
  const result = foo.value + bar.value;
  resetTracking();
  { // Explicitly depends on foo and bar
    foo.value;
    bar.value;
  }
  return result;
});
</script>

<template>
  <div>{{ baz }}</div>
</template>

@wanghanzhen
Copy link
Author

wanghanzhen commented Jun 14, 2024

@johnsoncodehk Thanks for your reply. I understand what you mean, but I think most developers will not deliberately write this logic.

Because of the flexibility of JS, it may happens in some relatively large projects like using Object.assign or making nested mutations carelessly. I think these computed cases are rare and I have found two cases in my project which were solved by using toRaw and shadow copy like { ...foo }.

What I'm worried about is I don't know if there are more cases that will cause the website getting unresponsive in production and unfortunately, it's difficult to find by static analysis.

@yyx990803
Copy link
Member

Note: #11135 has been reverted to avoid introducing regressions in the 3.4 line - the original issue is fixed in 3.5 already, so we will keep this one closed as we know it's fixed in a future release.

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

Successfully merging a pull request may close this issue.

6 participants