Vue 3 — Refs and Edge Cases

John Au-Yeung - Jan 25 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to use template refs and edge cases with Vue 3.

Template refs

Sometimes we may need to directly access the DOM.

To let us do that, we can assign a ref to the DOM element we want to access and then we can access it in our component code.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <input ref="input" />
    </div>
    <script>
      const app = Vue.createApp({
        methods: {
          focusInput() {
            this.$refs.input.focus();
          }
        },
        mounted() {
          this.focusInput();
        }
      });

      app.mount("#app");
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

to focus an input when the Vue instance mounts.

We assigned the input ref to our input.

Then we called focus on it to focus on the input.

We can also add a ref to component itself and use that to call focusInput .

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <custom-input ref="customInput"></custom-input>
    </div>
    <script>
      const app = Vue.createApp({
        mounted() {
          this.$refs.customInput.focusInput();
        }
      });

      app.component("custom-input", {
        methods: {
          focusInput() {
            this.$refs.input.focus();
          }
        },
        template: `<input ref='input' />`
      });

      app.mount("#app");
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

We put our input into the custom-input component.

And we have the focusInput method that calls focus on the input.

We assigned a ref to the custom-input component so that we can call the focusInput method of it.

And so we get the same result as we did before.

$refs are only populated after the component is rendered.

It’s the last resort for direct child component manipulation.

We should avoid accessing refs from templates and computed properties.

Edge Cases

There’re edge cases in Vue 3 that aren’t addressed by the usual constructs.

Controlling Updates

Usually, we rely on Vue’s reactivity system to update our component.

But sometimes, we may need to control how components are updated.

Vue provides ways to do that.

Forcing Updates

We can force updates by using the $forceUpdate method on a component.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <button @click="forceUpdate">update</button>
      <p>{{new Date()}}</p>
    </div>
    <script>
      const app = Vue.createApp({
        methods: {
          forceUpdate() {
            this.$forceUpdate();
          }
        }
      });
      app.mount("#app");
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

to do that.

We have a non-reactive expression in our template, so we can call $forceUpdate to update the component with a new date.

Create Static Components with v-once

We can create static component with the v-once directive.

It makes the content inside the element with the directive only update once.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <div v-once>
        hello world
      </div>
    </div>
    <script>
      const app = Vue.createApp({});

      app.mount("#app");
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

then Vue will never try to update the component once it’s rendered once.

Conclusion

Template refs let us access component methods and DOM elements directly.

We can also force updates with the $forceUpdate method and the v-once directive to display static content.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .