Create Vue 3 Apps with the Composition API — Read-Only Properties and Side Effects

John Au-Yeung - Jan 17 '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 comes with the Composition API built-in.

It lets us extract logic easily an not have to worry about the value of this in our code.

It also works better with TypeScript because the value of this no longer has to be typed.

In this article, we’ll look at how to create Vue 3 apps with the Composition API.

Read-Only Property

We can add a read-only property to our Vue 3 app with the composition API.

To add it, we use the readonly property:

<template>
  <div>{{ copy }}</div>
</template>

<script>
import { reactive, readonly } from "vue";
export default {
  name: "App",
  setup() {
    const original = reactive({ count: 0 });
    const copy = readonly(original);
    return {
      copy,
    };
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

We define the original reactive property with reactive .

Then we call readonly with original to create a read-only deep copy of the original.

And we return it, so we can use it.

Watch Reactive Properties

We can watch reactive properties with the watchEffect method.

For instance, we can write:

<template>
  <div>{{ count }}</div>
</template>

<script>
import { ref, watchEffect } from "vue";
export default {
  name: "App",
  setup() {
    const count = ref(0);
    watchEffect(() => console.log(count.value));

    setTimeout(() => {
      count.value++;
    }, 100);

    return {
      count,
    };
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

We call watchEffect with a callback to log the value of count when it’s updated in the setTimeout callback.

watchEffect returns a function that we can use to stop the watcher.

To use it, we write:

<template>
  <div>{{ count }}</div>
</template>

<script>
import { onBeforeUnmount, ref, watchEffect } from "vue";
export default {
  name: "App",
  setup() {
    const count = ref(0);
    const stop = watchEffect(() => console.log(count.value));

    setTimeout(() => {
      count.value++;
    }, 100);

    onBeforeUnmount(() => stop());

    return {
      count,
    };
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

We call stop in the onBeforeUnmount callback to stop the watcher when we’re unmounting the component.

Also, we can invalidate side effects with the onInvalidate function.

For instance, we can write:

<template>
  <div>{{ size }}</div>
</template>

<script>
import { onBeforeMount, reactive, watchEffect } from "vue";
export default {
  name: "App",
  setup() {
    const size = reactive({
      width: 0,
      height: 0,
    });

    const onResize = () => {
      size.width = window.innerWidth;
      size.height = window.innerHeight;
    };
    onBeforeMount(() => window.addEventListener("resize", onResize));

    watchEffect((onInvalidate) => {
      onInvalidate(() => {
        window.removeEventListener("resize", onResize);
      });
    });

    return {
      size,
    };
  },
};
</script>
Enter fullscreen mode Exit fullscreen mode

to call window.removeEventListener to remove the event listener in the onInvalidate callback.

The onResize function sets the size when we change the screen by attaching it as the listener for the resize event.

Conclusion

We can add read-only properties and watch side effects with Vue 3’s composition API.

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