Shane A. Stillwell
The :key to rerendering in Vue.js

The :key to rerendering in Vue.js

Every once in a while a technology comes along and fits like a glove. It solves problems in elegant ways and is immediately approachable from day one. One such technology is Vue.js. You have to understand, I’ve used many JavaScript frameworks. You can even say I wrote the book on advanced JavaScript.

I started with Angular back in the olden days of 0.8 and loved it, but like many, was wooed away to React while Angular tried to do a full rewrite for their 2.0 version (something you should never do). I then wrote React for many years and for the most part enjoyed its unconventional ways.

Then I heard of Vue.js and decided to write a little app in Vue. It was amazing, in about a day I created a cool little scheduling app. Vue has wonderful docs, simple to read and understand. I clearly remember coming across an issue “how do I render two table rows in each iteration of a for loop?” The answer was to use a template tag as the outer component for the loop. It’s not so much the solution, but merly, everytime I needed to do something special, Vue had already thought of it and made it convenient to implement. Another nice touch is the submit.prevent event modifier.

Once Again, Vue proves its worth.

The problem?

I want to force a form to reset after it’s been used.

In my case, I had a form for adding a reservation in CabinKey®. The resort owner would add a guest using the form, fill out the reservation. The next time they went to add a new reservation, the old values would still be in the form. The reusable form was a component that I called with a v-model so it would update some local input object I can use to submit the values.

  <NewGuestForm
    v-model="input"
  ></NewGuestForm>

Since Vue is efficient in rendering, when the resort owner moves away from this page, instead of destroying the rendered element, it simply hides until needed again. This is key, since it doesn’t destroy the element, it doesn’t receive new props or data. I tried a few things, including setting watchers in the form, but this became unwieldy.

When the solution becomes cumbersome, you’re heading in the wrong direction.

Then I read Michael Thiessen’s solution linked below. It dawned on me that the :key attribute wasn’t just used by the v-for loop to give each looped element a distinct id, but any element in Vue could have a :key attribute. To make Vue rerender the element, you change the :key.

With that new knowledge, all I needed to do was set the :key to a new value after it was submitted. The new code looks like this.

<template>
<NewGuestForm
  <!-- input.id is reset below after successful submission -->
  :key="input.id"
  v-model="input"
></NewGuestForm>
</template>
<script>
exports default {
  methods: {
    addReservation ({ id: personId } = {}) {
      this.$apollo.mutate({
        ...
      })
        .then(({ data }) => {
          // set the input to have new data that includes a new `id`. Date.now prints out the epoch in milliseconds
          this.input = { ...DEFAULT_INPUT, id: Date.now() }
        })
    },
  }
}
</script>

party time

Now that I know about it, I can see straight from the docs on :key.

The key special attribute is primarily used as a hint for Vue’s virtual DOM algorithm

Maybe I should go back and read the Vue.js docs more thoroughly, what else have I missed? Oh, yeah, $options, just figured that one out too. I guess you don’t need to put items in data() to be accessible to your template. 🙃

References

Photo by nextbike on Unsplash