DEV Community

Cover image for 3 Things You Should Try to Avoid in Vue.js
code plato
code plato

Posted on • Edited on

3 Things You Should Try to Avoid in Vue.js

1. Try not to write the inline script in the template if there are more than 2 lines of code

VSCode cannot check any syntax error of the inline script in the template. So try not to write the inline script in the template. If you write the inline script in the template, it's no different than writing code in Notepad. There are 2 drawbacks:

VS Code cannot check the syntax error

If you are using Typescript, VS Code can identify the syntax error for you. You might think I'd be able to spot those syntax errors, but actually, we don't. For example, in this code, the inline script only has 2 lines of code.

<div @click="alert('hello world'); doSomething();" />
Enter fullscreen mode Exit fullscreen mode

The even handler is

doSomething(event: Event) {
   // do something ...
}
Enter fullscreen mode Exit fullscreen mode

There is no errors in VS Code. But when you run this code, you will find that the event parameter is undefined.

If you extract the line move console.log('do something'); doSomething(); into a method sayHelloAndDoSomething()

sayHelloAndDoSomething() {
    console.log('do something');
    this.doSomething();
}
Enter fullscreen mode Exit fullscreen mode

Then you will see there is an error

Image description

It turns out that doSomething has a required parameter event. The worse thing is this inline script seems to be working fine. But the parameter event of doSomething arguments is undefined. We create a defect in this way. This example looks dumb. But there similar cases I've met at work.

Hard to debug the code in production

The inline script will be compiled in 1 line js code in production. It's not able to debug this code. If you put the code in a method/computed of the component. You can still be able to debug it even it's already minified.

Image description
If there is an error, we can still debug this code. It's not difficult to know what is the e or n variable based on the source code.

Imagine how convenient it will be if you can debug the code in production. That really help me for several times. So try to extract inline script code into component method/computed, it will help you eventually.

2. Try not to use watcher

Vue.js documentation already suggest us not to use watcher.
Image description

Why? Because watcher is an implicit dependency. Implicit dependency brings the following problems:

  • Logic becomes more scattered, and there is no explicit correlation between them. It makes it difficult to understand the code. This is especially difficult when troubleshooting.
  • When you update the feature, you won't be able to notice that somewhere a logic has been broken. Just because this logic is triggered by a watcher.

In addition to the problems brought by implicit dependencies, watcher has other problems of his own:

  • The watcher won't be triggered when Vue.js rendering the component as watch is lazy by default unless you use immediate: true. So if you expect some logic in a watcher will be called when v-if turn to true , you may be disappointed. We did meet a defect caused by this.
  • The watcher cannot be paused. Sometimes we don't want to disable the watcher, we just want to pause it. Unfortunately, watcher doesn't provide the pause feature. this comment mentioned that the only way to pause the watcher is doing a conditional check. When I have a similar problem at work, I usually add a flag like watcherEnabled to pause the watchers in some scenarios. But this flag also brought me some defects.

There are 5 better approaches than watcher

From child to parent

Use custom events

If you need to trigger the method of the parent component. You can use custom event

Image description

From parent to child

Move method from child to parent

If the metod you want to trigger is in child method. Instead of using $refs, it will be better to move the method to the parent component. Then you can directly call it or use custom event

Image description

Use ref attribute

If the method you want to trigger cannot be moved to the parent. Or you don't want to take the risk to refactor the task. You can use ref attribute

Image description

But remember that using $refs is not a good practice. $refs has its own problem as well. The component $refs is undefined when the component is rendering. So if you use $refs it in the template, it might be undefined. If you are using $refs in the computed. The computed might be broken. For example, there is a computed to get the child component scrollLeft attribute.

get childScollLeft() {
    return this.$refs.child.scrollLeft;
}
Enter fullscreen mode Exit fullscreen mode

This computed won't work as you expect. Because when the variable you want to watch in the computed is undefined at the beginning, then this computed will not be reactive. Not even after the $refs loaded.

Use props

If you want to update the child component UI. You can use props

Image description

From anywhere

Use Vuex

If you want to update the parent/child/sibling component UI. You can use Vuex. The only downside is that this may increase code complexity.

Image description

3. Try not to pass functions as props

Passing functions as props an anti-pattern in Vue.js. There is a sentence in the article that is really good.

As the application grows larger in size and other developers come on board, they will look at the child component code and have to figure out which callback function prop it is and where it is from.

That's the issue that I meet in my project. Sometimes I need to figure out where are those methods come from.

I agree with it. But this is not the main reason I don't recommend passing functions as props. The main reason is when I read the code it takes some effort to get familiar with the context of this component. If there is a function was passed as a prop, then I need to be familiar with the context of another component. If that were all it was, it wouldn't be so bad. The worse is I need to switch between different components contexts when reading the method.

I recommend using custom event instead of passing functions as props.

Top comments (0)