Subscribe on changes!

`watchEffect` should not have side effects on the response in `emits`

avatar
Sep 15th 2022

Vue version

3.2.39

Link to minimal reproduction

https://sfc.vuejs.org/#eNp9U8GO2jAQ/ZWpLwlqiKF7Kg2IqkLqoYceKvXiSzaZgLuJbdkOqEL59x07LGRZiZtn3sw8z/PzmX03Jj/2yFascJWVxoND35uNULIz2no4g8UGBmis7iCh0uQK/dCdueRzHoIwiWChKq2ch87tYR3a0+Qntq2Gv9q29adkFkpK919V0PSq8lIr0CoMaNFjnc7gLBTAt6OWdRiSH8u2x5AqT6X0oPAEv4lWOkwtrDfhyn9kh7r3qc1guVgsZsQBt166xu38GZZCDUIVfNyYdqXAI9GXHikCKA7LzfkcFxiGglMUs1KZ3sNx3uka27VghAs2QlGLbfW2A4GTjQSDTREVouKCX6lYxkYp511p8n9OK3qHuLu4AE6w1ahGyJG8IRbs4L1xK857ZV72ObHyLWHc9sqTDvNad9un/Ev+9JXX0vlpPkfXzZ+tPjm0xChYNhnOKXlEO7eoarRoH5Ld1b4jvMM+kAZOeoGBBHjzzSMH1thIhbtOepcFP2VwKn112DUNVv7Om6P1MNTSq08602i7Eb6+08WfTdk6jPhkcEpGJHNF9WUD6bVp9NHFpUDDlNMt5q3ep8ldUZLduC5tY1O84KQ8fIpREzo8cuZz7z39l23VyuqFbDZdxdtgkFgHsLNWW/iltYl9fGy8M+DwCqSwYko=

Steps to reproduce

Click the Error Loop button and you will see that the program enters a dead loop, which will loop once per second (because I added the delay).

I'm having a problem using emits in watchEffect and the program goes into a dead loop.

The watchEffect collects the dependencies in the emits and the dead loop is triggered as a result. I would like to know if this is a bug or a feature?

What is expected?

Personally I think it is a bug because responsiveness between components should be isolated by props and emits, otherwise it would be very complicated to troubleshoot.

What is actually happening?

which causes the program to enter a dead loop 😵

To be more clear:

This discussion has nothing to do with recursion. The topic of this issue is questioning about whether watchEffect should listen for responses in the emits event subscriber function.

avatar
Sep 15th 2022

this is not related to emits. see simpler demo or demo2

avatar
Sep 15th 2022

I think this is a bug, because reactive between child and parent components should be done through props, emits and other agreed-upon ways, so when I call emits in watchEffect I should not receive side effects from the parent component in the child component, they should be isolated by design intent.

This means, when I develop a component, I don't need to consider how the components work internally inside (the "black box") when it is using and, or when it is being used. The current side-effect polution breaks the "black box" (just like it jailbreaked the "black box").

Or summarize in Chinese:

这意味着我在开发一个组件时不需要考虑其正在使用的组件和组件被使用时其黑箱内部是如何编写的;而现在的这个副作用泄漏破坏了这种黑箱规则。

avatar
Sep 17th 2022

I also think this is a bug, which adds to the confusion of the code.

avatar
Sep 17th 2022

this is not related to emits. see simpler demo or demo2

These two demos are not equivalent to the above demo, I think it is still related to emits.

avatar
Sep 17th 2022

this is not related to emits. see simpler demo or demo2

These two demos are not equivalent to the above demo, I think it is still related to emits.

The reason is the same, the synchronous call avoids recursive calls based on whether it is equal to activeEffect or not. But asynchronous calls have the activeEffect cleared, so recursive calls can't be avoided.

avatar
Sep 17th 2022

I know the concept you are talking about, but the issue I want to discuss now has nothing to do with recursion. The topic of this issue is questioning about whether watchEffect should listen for responses in the emits event subscriber function.

avatar
Sep 17th 2022

IMO, It does not make sense to execute emits in the effect function(computed,watch...). should avoid executing emits in effect functions

avatar
Sep 17th 2022

hm, why? I think that's a pretty common scenario

avatar
Sep 17th 2022

IMO, It does not make sense to execute emits in the effect function(computed,watch...). should avoid executing emits in effect functions

I often write this way, and my code will often need to notify the parent components when the state changes.

avatar
Sep 17th 2022

I agree this is a bug, and I think it should be safe to pause tracking before emit() calls the handler. I sent a PR to discuss about

@edison1105 What do you think?

avatar
Sep 17th 2022

I agree this is a bug, and I think it should be safe to pause tracking before emit() calls the handler. I sent a PR to discuss about

@edison1105 What do you think?

Agreed

avatar
Sep 27th 2022

This is not a bug. watchEffect by definition tracks during its sync operation.

If you want safe, non-tracking side effects, use watch with a callback - it explicitly separates the "tracking" and the "side effects" - pretty much designed for this case.