When v-memo can tweak v-for performance
Tags: vue, ux
Published: 2022-06-11 07:49:07

A year ago, my first task as a frontend developer was to rebuild a learning management system for an online education website of our company. At that time I only know little about framework and I was asked to build the project with Vue. It was stressful, but luckily, Vue and Vuetify are easy to use, so everything went great, and I can tell that my supervisors are satisfied with my work. 

But there was one thing annoyed me that I kept in my mind. I had a long list with checkboxes rendered by v-for or Vuetify table, the response of checkbox lag badly. My solution to it was making pagination, but sometimes it's easier to use when the whole list is shown. The solution isn't perfect and a bigger issue is that I don't know what's the cause.

Later, I have another project that needs to render a long list and checkboxes. Again, I ran into the same issue. I use different UI libraries for these two projects, so I was thinking maybe it's because the checkboxes components that causes bad performance. So I decided to make one myself, I made a very simple [Gmail like checkbox](https://dev.to/gohomewho/how-to-make-a-gmail-like-checkbox-4o5k) and it solves the issue. At least, it looks like.

Until recently, I watched a tutorial ["Are You Following This Vue Best Practice?"](https://www.youtube.com/watch?v=S2wj8VX9O0M) on Youtube. Before that, I was not aware of that props update will cause child components to rerender and update even there is nothing to change. So best practice is we need to make props passing to be as stable as possible.

## Ideal checkbox behavior
An ideal checkbox should react to change instantly. This is a [checkbox](https://next.vuetifyjs.com/en/components/checkboxes/#checkboxes) from Vuetify 3. 
![toggle Vuetify 3 checkbox](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a9jxy3tp2lqadhba6wtw.gif)

## Checkbox behavior in a long v-for list 
Checkbox can lag as the length of a list grows. When we use `v-model` on checkboxes binding them to an array named `selected`, `selected` changes when a checkbox changes. We already know that props update will trigger child component update, so when `selected` changes, it will then trigger all checkboxes to update.

There are 1000 items. Checkbox's response to toggle becomes lagging.
![toggle Vuetify 3 checkbox in long list](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9poadgcuk87e3uy5js59.gif)

If your machine is fast, you may not experience the issue as shown in the image.
{% codepen https://codepen.io/ga676005/pen/OJQaQYL %}


## Make props stable
To avoid the prop passed to checkboxes keep changing, instead of binding checkbox's `v-model` to a same prop, we can create a new list `localList` that add a `isChecked` property to each item, and bind each checkbox to their respective `item.isChecked`, thus we limit the props change. We can then make a computed value to compute the `selected` result. 

But checkboxes are still lagging badly.
![toggle Vuetify 3 checkbox in long list is still lagging](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51s7bnde7axg6fjr2mpf.gif)

Why is this still happening after we have limited the props change? 
Because now we are changing the list for `v-for`, although we only change `item.isChecked` of one item, Vue creates VNodes for each item in the `localList` and diffing them. Since the checkbox components from UI libraries are complex, it takes some time to compute.
{% codepen https://codepen.io/ga676005/pen/dydQmGa %}


## v-memo
This is when we need [v-memo](https://vuejs.org/api/built-in-directives.html#v-memo). By specifying `v-memo`, We can explicitly tell Vue when to update the nodes in `v-for` and skip those who don't need to be patched at all. `v-memo` accept an array of dependences, it can only be used with `v-for` on the same element. if all dependencies of a node in `v-memo` remain the same, that node won't update. 


```vue
<div
  v-for="item in localList" 
  v-memo=[item.isChecked]
  :key="item.id"
> 
  ...
</div>
```
This is saying if `item.isChecked` of this node doesn't change, it don't need to be patched. Without specifying `v-memo`, one item in `localList` changes can cause Vue to update all nodes. This is different than binding all checkbox to a same prop (an array), but they both affect performance.

Now toggle checkbox can get instant response. 
![toggle checkbox will change instantly after adding v-memo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x4hgeoaqvi0yfrgwqdmc.gif)


Only add `v-memo=[item.isChecked]` compared to last example.
{% codepen https://codepen.io/ga676005/pen/RwQqyGK %}



## Wrap up
v-memo allows us to tweak the performance when we need to render a long list especially a interactive one. v-memo is a relatively new feature and it does not exist in Vue 2. In my case, I cannot use v-memo to update my first project, but I can still replace the complex checkbox component with my own simple checkbox component. In fact, if the checkbox component is simple, binding v-model to an array won't be a problem. The main idea of this article is to find out what could cause a component to update and sneakily becomes a performance issue.