본문 바로가기
개발/Vue.js

Vue.js Composition API 알아보기

by 궁즉변 변즉통 통즉구 2022. 4. 3.
반응형

Composition API

  • 컴포넌트에서 사용하는 특정 기능의 코드를 유연하게 구성할 수 있는 함수 기반의 API
  • Vue3에서 가장 중요한 핵심 기능
  • [기존]개발 방식은 연관성 있는 로직들이 data, computed, methods 등에 흩어져 있어서 프로젝트 규모가 커질수록 관리, 추적에 어려움
    => Composition API의 setup()을 사용하여 관련 코드들을 묶어서 구현할 수 있어서 코드 관리, 추적이 용이
  • [기존] Mixin을 통한 컴포넌트 기능 재사용 부분도  오버라이딩 문제나 다중 Mixin 상속 시 컴포넌트 관리가 어려워 짐
    => Composition API를 통해서도 공통기능 제공 가능

 

setup() 메소드

- 샘플 코드

<template>
  <div>
    <h2>{{ count }}</h2>
    <h2>{{ countDouble }}</h2>
    <button @click="plus">Plus</button>
    <button @click="minus">Minus</button>
  </div>
</template>
<script>
import { ref, computed } from "vue";

const countFunc = () => {
  // data와 같은 반응형 처리를 위해 ref를 사용하여 0값을 세팅
  const count = ref(0);
  const countDouble = computed(() => count.value * 2);

  // ref는 값에 접근 시 value 속성 사용
  const plus = () => ++count.value;
  const minus = () => --count.value;

  return { count, countDouble, plus, minus };
};

export default {
  name: "CountView",
  setup() {
    const { count, countDouble, plus, minus } = countFunc();

    return {
      count,
      countDouble,
      plus,
      minus,
    };
  },
};
</script>

- 결과

위의 샘플 코드에서 보면 기존에 data, computed, methods를 사용해서 구현했어야 되는 코드들이 setup()을 통해서 호출되는 countFunc()내에 모두 포함이 되어 있다. 이렇게 하나의 기능에 해당하는 코드들을 한곳에 모아서 관리가 가능함으로 규모가 커졌을 때 훨씬 코드관리가 쉬워질 것 같다.

setup()메소드는 라이프사이클 Hook "beforeCreatecreated" 사이에 발생함으로 Composition API에서 onBeforeCreate, onCreated Hook은 setup()안에 코드를 작성하면 된다.

 

반응형 데이터 - reactiveref

기존에 data 속성을 통해서 관리되던 반응형(자동 데이터 바인딩) 데이터들은 Composition API에서는 reactive 또는 ref를 통해서 관리한다.

- 샘플코드

<template>
  <div>
    <h2>{{ reactiveEx.num }}, {{ reactiveEx.message }}</h2>
    <h2>{{ refEx }}</h2>
    <h2>{{ refExObj.num }}, {{ refExObj.message }}</h2>
  </div>
</template>
<script>
import { ref, reactive, isRef } from "vue";

export default {
  name: "ReactiveRefView",
  setup() {
    // 1. reactive 샘플
    const reactiveEx = reactive({
      num: 0,
      message: "reactive message",
    });
    console.log(reactiveEx.message);
    console.log(isRef(reactiveEx)); // false

    // 2. ref Primitive타입 샘플
    const refEx = ref("ref message");
    console.log(refEx.value); // value속성 사용
    console.log(isRef(refEx)); // true

    // 3. ref 객체타입 샘플
    const refExObj = ref({
      num: 1,
      message: "ref Obj message",
    });
    console.log(refExObj.value.message); // value속성 사용
    console.log(isRef(refExObj)); // true

    return {
      reactiveEx,
      refEx,
      refExObj,
    };
  },
};
</script>

- 결과

Composition API의 reactive객체만 받을 수 있고, 값에 대한 접근은 일반적인 객체 값 참조 방법과 동일하다. ref 같은 경우 객체 및 Primitive타입을 모두 받을 수 있고, 값에 대한 접근 시 value 속성을 사용한다. ref 객체는 원본 값을 value라는 속성에 담아두고 변경을 감시하는 객체이며, reactive는 원본 객체 자체에 변경을 감지하는 옵저버를 추가하여 그대로 반환한 값이라고 한다. 추가적으로 isRef()메소드를 사용해서 ref 여부인지를 판단할 수 있는데 ref 값과 reactive 값에 따라 다르게 처리해야 할 경우 사용하면 된다.

 

반응형 데이터 - toRefs()

- 샘플코드

<template>
  <div>
    <input type="text" v-model.number="num" />
    <h2>{{ numDouble }}</h2>
  </div>
</template>
<script>
import { reactive, computed, toRefs } from "vue";

const countFunc = () => {
  const numbers = reactive({
    num: 0,
    numDouble: computed(() => numbers.num * 2),
  });
  // return numbers; // 반응형으로 동작 안함
  return toRefs(numbers);
};

export default {
  name: "ToRefsView",
  setup() {
    // reactive객체 값들을 분해해서 받기 때문에 기본적으로 반응형이 동작 안함 => toRefs()사용 필용
    const { num, numDouble } = countFunc();

    return {
      num,
      numDouble,
    };
  },
};
</script>

- 결과

countFunc()에서 reactive 객체를 선언하고 setup()에서 값을 분해해서 재할당받아서 사용하는 경우 기본적으로 반응형으로 동작을 하지 않게된다. 이때 toRefs()를 사용하면 반응형을 그대로 유지가 가능하다.

 

Composition API 전역 설정

많이 사용되는 공통기능 같은 경우 Mixin과 같이 전역으로 구성을하고 사용한다.

- 별도 javascript 파일 선언(common.js)

import { ref, computed } from "vue";

const countFunc = () => {
  const count = ref(0);
  const countDouble = computed(() => count.value * 2);

  const plus = () => ++count.value;
  const minus = () => --count.value;

  return { count, countDouble, plus, minus };
};

export { countFunc };

- vue 파일에서 import 후 사용

<template>
  <div>
    <h2>{{ count }}</h2>
    <h2>{{ countDouble }}</h2>
    <button @click="plus">Plus</button>
    <button @click="minus">Minus</button>
  </div>
</template>
<script>
// js import
import { countFunc } from "../../common.js";

export default {
  name: "CountView",
  setup() {
    const { count, countDouble, plus, minus } = countFunc();

    return {
      count,
      countDouble,
      plus,
      minus,
    };
  },
};
</script>

- 결과

 

Composition API LifeCycle Hook

Composition API에서도 컴포넌트 LifeCycle Hook 을 사용할 수 있다.

- 샘플코드

<template>
  <div>
    <h2>{{ message }}</h2>
    <button @click="change">Update</button>
  </div>
</template>
<script>
import {
  ref,
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
} from "vue";

export default {
  name: "LifeCycle",
  setup() {
    // onBeforeCreate(), onCreated()는 불필요 => setup내에 작성
    console.log("setup!!");

    const message = ref("Message");
    const change = () => (message.value = "Change Message");

    onBeforeMount(() => console.log("onBeforeMount!!"));
    onMounted(() => console.log("onMounted!!"));
    onBeforeUpdate(() => console.log("onBeforeUpdate!!"));
    onUpdated(() => console.log("onUpdated!!"));
    onBeforeUnmount(() => console.log("onBeforeUnmount!!"));
    onUnmounted(() => console.log("onUnmounted!!"));

    return {
      message,
      change,
    };
  },
};
</script>

- 결과

 

참고 자료 :

https://geundung.dev/102

 

 

 

반응형

댓글