We should avoid using watch
in Vue. I'm not saying it's bad; we should just treat watch
(and watchEffect
) as a last resort. watch
is a very reliable tool. It is the simplest and laziest way to achieve a function. It can almost guarantee 100% triggering, thus covering your needs. But the problem is that sometimes it covers too much. watch
has the following disadvantages:
Disadvantages
1. Implicit Dependency
watch
creates an implicit dependency.
An implicit dependency is a hidden relationship between components in a system where one component relies on another without being explicitly stated.
An explicit dependency occurs when component A directly calls component D, making the relationship clear and easy to trace.
Implicit dependency means that component A eventually calls component D in an unobvious way, creating a connection between them.
Although explicit dependencies seem easier to maintain, a system full of them would lack flexibility. For example, vue-router
is an implicit dependency, and implicit dependencies are essential for building frameworks. However, using them in business code increases maintenance difficulty.
Here is a great article that explains the disadvantages of implicit dependencies:
Side Effects in Code: Why They Matter and How to Avoid Them
Although this article does not explicitly mention implicit dependencies
, side effects are essentially how watch
operates in Vue.
Side effects create implicit dependencies between components, increasing the chance of bugs. For instance, in our discussion, I noted: "If a method assumes that a specific member variable will be updated beforehand, you’ve built a trap for the next developer — or even for yourself six months later."
2. Difficult to Trace the Source of Changes
When an error occurs, it is difficult to determine which piece of code initially triggered the change. If you are debugging in a local environment, it's easy to check the stack trace. But if you are troubleshooting on QA, CM, or PROD and are unaware of a watch
, debugging can become a nightmare.
A real-world example: while working on one of the page of our project, we encountered a defect that seemed to originate from the data initialization. However, we didn't realize that the data were initialized twice—once via a watch
. If both initializations worked correctly, the duplicate execution would go unnoticed. But when bugs inevitably appear, identifying the source of the error becomes critical in measuring code quality.
3. Creates Tight Coupling, Making Refactoring Difficult
Using watch
can tightly couple different parts of the code. Initially, we knew that code A triggered code B through watch
. Over time, additional code was introduced—code C also triggered code B through watch
. Then, a third engineer, seeing the existing pattern, added code D, further expanding the web of dependencies. This results in increased coupling, making the code harder to maintain.
This article discusses the dangers of tight coupling:
Code Coupling: Reducing Dependency in Your Code
You’ve no doubt encountered this effect: you make a change in one corner of the system and it breaks code in a far, far distant corner. You might not even spot such a defect, particularly if you don’t do extensive regression testing with each release. That, of course, means your unfortunate customer will likely be the one who spots the defect.
A watch
is like a spider web—it captures any logic that falls into its scope. If you watch
a global variable, such as savedSession
, its impact could extend across the entire project.
A project with excessive watch
usage resembles the image above.
4. May Cause Infinite Loops
If watch
A triggers watch
B, and watch
B triggers watch
A, you create an infinite loop.
A real example: while developing QuotesPage.vue
, I was a big fan of watch
and added five or six of them on a single page. This led to an infinite loop when the page attempted a "relaxation" operation. At the time, there was no good way to suspend a watcher. See this answer from Evan You, the creator of Vue.js:
The only way to suspend a watch
is to include a conditional check. I had to add some variables like watcherEnabled
disable the watch
when necessary. After I stopped using watch
, I was able to say goodbye to this ugly workaround.
5. Hard to Read and Understand
When reviewing the logic behind a watch
, you often need to navigate between multiple files or distant parts of the same file.
You might need to jump across different areas of the project to understand the full logic flow.
Better Solutions
There are better alternatives to watch
. Consider the following before using a watcher:
- Directly call the method if they are in the same component.
- Use
computed
properties if you only need to display something. - Use custom events to trigger methods in a parent component.
- Use lifecycle hooks like
app:rendered
,page:start
,definePageMeta
in Nuxt, oronMounted
in Vue.
When to Use watch
Despite its drawbacks, watch
is still useful in some cases:
- When you need to update something, but custom events cannot achieve the desired behavior.
By using watch
cautiously and considering alternatives first, you can write more maintainable and predictable Vue applications.
Top comments (0)