본문 바로가기
Web/JavaScript

[Vue3] Composition API

by llHoYall 2021. 6. 25.

Composition API is a function-based API added to Vue3.

Let's take a look at this what is this.

Create a Project

2021.06.02 - [Web/JavaScript] - [Vue3] Getting Started with Vue3 + TypeScript + TailwindCSS

First of all, create a project for testing our example.

Traditional Methods

Let's create an adder component in the traditional way.

 

components/composition_api.vue

<template>
  <div class="p-4 flex flex-col justify-start items-center">
    <h2 class="mt-8 mb-2 text-xl font-medium text-green-600">
      Traditional Method
    </h2>
    <div class="mt-2 flex justify-center">
      <input
        type="number"
        v-model.number="num1"
        @change="addTwoNumbers"
        class="w-2/12 px-2 py-1 text-gray-700 outline-none"
      />
      <div class="mx-4 text-2xl">+</div>
      <input
        type="number"
        v-model.number="num2"
        @change="addTwoNumbers"
        class="w-2/12 px-2 py-1 text-gray-700 outline-none"
      />
      <div class="mx-4 text-2xl">=</div>
      <div class="text-2xl">{{ result }}</div>
    </div>
  </div>
</template>

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

export default defineComponent({
  name: "CompositionAPI",
  data: () => {
    return {
      num1: 0,
      num2: 0,
      result: 0,
    };
  },
  methods: {
    addTwoNumbers: function () {
      this.result = this.num1 + this.num2;
    },
  },
});
</script>

And render this.

 

App.vue

<template>
  <div class="my-4 flex justify-center items-center">
    <CompositionAPI />
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import CompositionAPI from "./components/composition_api.vue";

export default defineComponent({
  name: "App",
  components: {
    CompositionAPI,
  },
});
</script>

We are familiar with creating components in this way.

Changing with Composition API

Let's briefly organized this code using Composition API.

<template>
  <div class="p-4 flex flex-col justify-start items-center">
    <h2 class="mt-8 mb-2 text-xl font-medium text-green-600">
      Composition API Method
    </h2>
    <div class="mt-2 flex justify-center">
      <input
        type="number"
        v-model.number="state.num1"
        class="w-2/12 px-2 py-1 text-gray-700 outline-none"
      />
      <div class="mx-4 text-2xl">+</div>
      <input
        type="number"
        v-model.number="state.num2"
        class="w-2/12 px-2 py-1 text-gray-700 outline-none"
      />
      <div class="mx-4 text-2xl">=</div>
      <div class="text-2xl">{{ state.result }}</div>
    </div>
  </div>
</template>

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

type State = {
  num1: number;
  num2: number;
  result: ComputedRef;
};

export default defineComponent({
  name: "CompositionAPI",
  setup() {
    const state: State = reactive<State>({
      num1: 0,
      num2: 0,
      result: computed(() => state.num1 + state.num2),
    });
    return { state };
  },
});
</script>

The setup() is where to implement Composition API.

We defined state using reactive and computed.

And modify the usage.

We could remove event in the input element and should use variables with prefix state.

It performs the same functioning with shorter and more beautiful code.

Separate Composition API

Let's separate our composition API for general usage in the project range.

 

common.ts

import { computed, ComputedRef, reactive, ToRefs, toRefs } from "vue";

type State = {
  num1: number;
  num2: number;
  result: ComputedRef;
};

export const addTwoNumbers = (): ToRefs => {
  const state: State = reactive<State>({
    num1: 0,
    num2: 0,
    result: computed(() => state.num1 + state.num2),
  });
  return toRefs(state);
};

We separated our composition API into a separate file and made it under the name addTwoNumbers.

 

<template>
  <div class="p-4 flex flex-col justify-start items-center">
    <h1 class="text-2xl font-medium text-green-400">Composition API</h1>

    <h2 class="mt-8 mb-2 text-xl font-medium text-green-600">
      Composition API Method
    </h2>
    <div class="mt-2 flex justify-center">
      <input
        type="number"
        v-model.number="num1"
        class="w-2/12 px-2 py-1 text-gray-700 outline-none"
      />
      <div class="mx-4 text-2xl">+</div>
      <input
        type="number"
        v-model.number="num2"
        class="w-2/12 px-2 py-1 text-gray-700 outline-none"
      />
      <div class="mx-4 text-2xl">=</div>
      <div class="text-2xl">{{ result }}</div>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import { addTwoNumbers } from "../common";

export default defineComponent({
  name: "CompositionAPI",
  setup() {
    let { num1, num2, result } = addTwoNumbers();
    return { num1, num2, result };
  },
});
</script>

We imported our composition API and setup it.

And we can use it as local things.

with Lifecycle Hooks

In the Composition API, setup() runs between beforeCreate and created.

Let's check the hooks inside the setup().

import {
  defineComponent,
  onBeforeMount,
  onBeforeUnmount,
  onBeforeUpdate,
  onErrorCaptured,
  onMounted,
  onRenderTracked,
  onRenderTriggered,
  onUnmounted,
  onUpdated,
} from "vue";

export default defineComponent({
  name: "CompositionAPI",
  setup() {
    onBeforeMount(() => {
      console.log("Component is in beforeMount");
    });
    onMounted(() => {
      console.log("Component is mounted");
    });
    onBeforeUpdate(() => {
      console.log("Component is in beforeUpdate");
    });
    onUpdated(() => {
      console.log("Component is updated");
    });
    onBeforeUnmount(() => {
      console.log("Component is in beforeUnmount");
    });
    onUnmounted(() => {
      console.log("Component is unmounted");
    });
    onErrorCaptured(() => {
      console.log("Component captured error");
    });
    onRenderTracked(() => {
      console.log("Component tracked rendering");
    });
    onRenderTriggered(() => {
      console.log("Component triggered rendering");
    });
  },
});

Feel free to test the lifecycle hooks.

with Provide and Inject

Provide and Inject are also available in the Composition API.

Let's send our result using

provide

to a child.

<template>
  <div class="p-4 flex flex-col justify-start items-center">
    ...
    <h2 class="mt-8 mb-2 text-xl font-medium text-green-600">
      Provide / Inject
    </h2>
    <PIChild3 />
  </div>
</template>

<script lang="ts">
import { defineComponent, provide } from "vue";
import { addTwoNumbers } from "../common";
import PIChild from "./pi_child.vue";

export default defineComponent({
  name: "CompositionAPI",
  components: { PIChild },
  setup() {
    let { num1, num2, result } = addTwoNumbers();
    provide("result", result);
    return { num1, num2, result };
  },
});
</script>

We need to provide the data and a name as a key.

 

components/pi_child.vue

<template>
  <h2 class="mt-8 mb-2 text-xl font-medium text-green-600">PI Child</h2>
  <div>{{ result }}</div>
</template>

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

export default defineComponent({
  name: "PIChild",
  setup() {
    const result = inject("result");
    return { result };
  },
});
</script>

And when using the provided data, inject has to be used with the name as a key.

Conclusion

In this posting, we learned about Composition API.

I love this feature.

I hope you love this feature too.

'Web > JavaScript' 카테고리의 다른 글

[Vue3] Vuex Usage  (0) 2021.06.26
[Vue3] Mixins  (0) 2021.06.26
[vue3] Plugins  (0) 2021.06.25
[Vue3] Custom Directives  (0) 2021.06.24
[Vue3] Send Data from Ancestor Component using Provide and Inject  (0) 2021.06.20

댓글