3 Things You Should Try to Avoid in Vue.js
Tags: vue, javascript
Published: 2022-04-03 18:07:44

# 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();" />
```

The even handler is
```
doSomething(event: Event) {
   // do something ...
}
```

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();
}
```
Then you will see there is an error

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2g2szo2tvqjnq4vw3vxk.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54wkst1z7w663ou4gr0n.png)
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](https://v2.vuejs.org/v2/guide/computed.html?redirect=true#Computed-vs-Watched-Property) already suggest us not to use watcher.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x3wvzjwo3stavfyea1gv.png)

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](https://github.com/vuejs/vue/issues/1829#issuecomment-157944069) 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](https://v2.vuejs.org/v2/guide/components-custom-events.html?redirect=true)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/azragve5odwmm6lh3az8.png)

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qy542e10v59wf4dmv9ns.png)
### 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](https://v2.vuejs.org/v2/guide/components-edge-cases.html#Accessing-Child-Component-Instances-amp-Child-Elements)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c4kmj9o99pa1a34gjh2h.png)

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;
}
```

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](https://v2.vuejs.org/v2/guide/components-props.html?redirect=true)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r122jroa2mb6lvq1sb66.png)

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0e63hk4fnrlgf1mm5x9b.png)

# 3. Try not to pass functions as props
[Passing functions as props an anti-pattern in Vue.js](https://medium.com/js-dojo/passing-functions-as-props-an-anti-pattern-in-vue-js-b542fc0cf5d). 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](https://v2.vuejs.org/v2/guide/components-custom-events.html?redirect=true) instead of passing functions as props.