How to Make a Component (and a computed prop)

The main difference when creating a component is the change to a single setup() function rather than having explicit methods and computed objects with functions within those. It also replaces the data section of the component. For example, using the options API looks like this:

<template>
  <h1>{{ myMesage }}</h1>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    message: {
      type: String,
      required: true,
    },
  },
  computed: {
    myMessage(): string {
      return this.message.toUpperCase();
    },
  },
});
</script>

Using the Composition API looks like this:

<template>
  <h1>{{ myMesage }}</h1>
</template>

<script lang="ts">
import { computed, defineComponent, toRefs } from "vue";

export default defineComponent({
  props: {
    message: {
      type: String,
      required: true,
    },
  },
  setup(props) {
    const { message } = toRefs(props);
    const myMessage = computed(() => message.value.toUpperCase());
    return {
      myMessage,
    };
  },
});
</script>

Both of these components are equivalent.

Computed Props

You can see in the example above the computed function. This allows you to define how data should be manipulated into the resulting value. The value will be reactive, which just means it will trigger the component to update when the values it uses change.

Equivalent of a Data Value

The options API way:

<template>
  <h1>Hello {{ text }}!</h1>
</template>

<script>
import { defineComponent } from "@vue/composition-api";

export default defineComponent({
  data: () => ({
    text: "",
  }),
});
</script>

The composition API way:

<template>
  <h1>Hello {{ reactive }}!</h1>
  <h1>Non-reactive hello {{ nonReactive }}</h1>
</template>

<script>
import { defineComponent, ref } from "@vue/composition-api";

export default defineComponent({
  setup() {
    const nonReactive = "world";
    const reactive = ref("Ben");

    return {
      nonReactive,
      reactive,
    };
  },
});
</script>

The new way has two different kinds of values. Reactive and non reactive. Non reactive values when they are changed to not trigger a re-render of your component, where as if a reactive value changes, then your component will update. So if you need to see updates and the value isn't a constant, use the helper ref() function.

Equivalent of a Method

The options API:

<template>
  <h1>My Value: {{ text }}</h1>
  <button @click="onButtonClick">Click</button>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  data: () => ({
    text: "Unclicked",
  }),
  methods: {
    onButtonClick() {
      this.text = "It was clicked!";
    },
  },
});
</script>

The composition API:

<template>
  <h1>My Value: {{ text }}</h1>
  <button @click="onButtonClick">Click</button>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";

export default defineComponent({
  setup() {
    const text = ref("Unclicked");

    function onButtonClick() {
      text.value = "It was clicked!";
    }

    return {
      text,
      onButtonClick,
    };
  },
});
</script>

The new way relies on passing a function via the return value of the setup method. This uses scoping to hold references to the data that the function manipulates.