7 tips for VueJS developers5 min read

Sharing

Almost a year ago, I started a GitHub repository named “Today I Learned“. It’s a place where I put little tricks I learned while developing. I talk about it in this article : Ce que j’ai appris aujourd’hui ! I’ve been filling it up since, and I think it’s time I share with you my favorite tips about VueJS.

#1 Prevent VueJS to reuse a component when changing page

VueJS is built to make your app as fast as possible. And like many front-end frameworks, it does a great job at reusing graphic elements to avoid destroying and rebuilding them. It’s much faster this way !

But sometimes it brings some unwanted behavior. I have this page, with a table inside. And when I change page, I keep the same layout, only the data changes. I’ve added a nice animation to my table for when a row is added, or when it is rearranged. But when I change page, my table is de-populated and re-populated with the new data, which triggers the animation. I don’t want that. I find it over dynamic.

To prevent this behavior, I found that I could ask VueJS to not reuse my table, but to build a new one for each page. And there is a very simple way to do it: add a :key attribute to the component with a value that is different for each page.

#2 Add v-model capability to a custom component

v-model is one of the iconic features of VueJS. It’s part of the first thing we’re taught to use when learning the framework. And that’s probably the reason why we forget (or even don’t know) how it works. As stated in the official documentation, v-model replace the use of both :value and @input. That is how the magic happens. When the linked variable changes(:value), the value of the input is updated, and when the user types something in the input (@input), the variable is updated.

So all you have to do in your custom component is add a prop named value, and emit a custom event named input. Here is an example for a custom color picker:

export default {
  props: {
    value: {
      type: String,
      required: true
    }
  }

  methods: {
    onClick(color) {
      this.$emit("input", color);
    },
  },
};

#3 Conditional CSS classes

Say you want a div‘s background to be colored when it is selected in a list. The easy way to do this is to add a CSS class to that div when a condition is met (item is selected).

VueJS provides a very simple syntax for binding CSS classes to an HTML object:

<p
  :class="{
            'class-1': condition_1,
            'class-2': condition_2,
          }"
>
  Hello !
</p>

#4 How to not cache VueX getters

By default, VueX getters results are updated when the store is updated and then the result is cached. This way the getter’s computation is done only if a change in the store occurs.

But if the result of the getter is a computation based on elements outside the store, like a date for example, it becomes a problem. Because the computation will be done once, at the initialization of the store, and never again.

On way to solve this issue is to assign a function to a getter. This way, each time the getter is called, the function is executed. Nothing can be cached.

const getters = {
  userIsAuthenticated: (state) => () => {
    return state.sessionTimeout != null && Date.now() < state.sessionTimeout
  },
}

Do not forget the parenthesis when calling this particular getter: store.getters.userIsAuthenticated()

#5 Stub an API call with an acceptable delay

VueJS (and js applications in general) has a special way to handle time : read this article about tasks, microtasks, queues and schedules.

While testing a simple click on a button, triggering the display of a loader and the fetch of data from the server, I encountered some trouble. Here is an example of a function to test:

onClick() {
  this.loading = true
  fetchMyApp('auth/login', {
      method: 'POST',
      body: JSON.stringify({
        email: this.email,
        password: this.password,
      }),
    })
    .then(() => {
      // Login
    })
    .catch(() => {
      // Handle error
    })
    .finally(() => {
      this.loading = false
    })
})

I want to stub the fetchMyApp function, which is a promise, so I use the SinonJS stub.resolve() function.

In the test function, after a click, we need to use Vue.nextTick() to wait for the DOM to be updated. Problem is, the function stubbed with SinonJS actually resolves before the view is updated. It’s not visible to the naked eye, but when testing, it fails.

Now the solution. We need to delay the resolving of the stubbed Promise. According to the quoted article, a setTimeout() with a timeout of 0 will be enough, because it will resolve at the next task loop, whereas Vue.nextTick() will resolve within a microtask loop. So here is how it should be done:

stub.returns(
  new Promise((resolve) => {
    setTimeout(() => resolve(), 0)
  }),
)

#6 Explore JS with vue devtools

Did you notice that in vue devtool, in the “Components” tab, when a component is selected, a little = $vm0 appears next to it? And when you select an other component, it transforms to = $vm1. And so on to = $vm4.

Well those variables ($vm0, $vm1…) can then be used in the navigator console to explore the virtual DOM of this component. How great is that!?

#7 Dynamically remove watcher

When dynamically creating a watcher (using the this.$watch method), it actually returns a function. When this function is called, it destroys the watcher. Who would have known ?

initWatchAction() {
  this.unwatchAction = this.$watch(
    'actionIsDone',
    this.watchAction,
  )
},

watchAction() {
  if (this.actionIsDone) {
    this.unwatchAction()
  }
},

I hope you enjoyed these few tips. Do not hesitate to “Star” my GitHub repo to be notified of new tricks, and not only for VueJS.

Have a nice day !

Related Posts

Leave a Reply