vue composition api

options api

정의

  • data, method 등을 options object에 담아서 정의하는 방식.

문제

  • 관련 로직이 분산되어 있음
  • 믹스인으로 로직을 재사용하는데에 한계가 있음
    • 컴포넌트 데이터의 출처가 모호해짐
  • 개발할 때, IDE에서도 로직을 파악하기 어려움
  • 이름이 중복될 수 있음
  • 타입스크립트 지원이 제한적

image 이미지 출처: https://vueschool.io/articles/vuejs-tutorials/options-api-vs-composition-api/

composition api

특징

  • 반응형 api
  • 라이프사이클 훅을 지원
  • 의존성 주입
  • 관심사를 한데 모을 수 있어 읽고 이해하기 쉬움
  • 문맥에 따라 사용하는 부분들의 이름을 다시 지을 수 있음
  • 로직을 재사용하기 쉬움
  • 타입스크립트 지원이 잘됨
    • ref의 초기값으로 타입 추론 가능
    • computed가 반환하는 값으로 타입 추론 가능
    • interface로 reactive data의 타입을 정의할 수 있음
  • (vue2.7 버전부터 빌트인 되어 있다.)

setup

  • setup 은 Vue가 컴포넌트 생성전에 props가 전달되면 자동으로 실행됨.
  • 인자로 props, context를 받는다.
  • setup이 불릴 때 컴포넌트가 생성되지 않았으므로 this로 접근 불가
<script>
export default {
  props: {
    name: String,
    price: Number,
  },
  setup(props) {
    console.info('name', props.name)
    console.info('price', props.price)
  }
}
</script>
image

context

  • attrs
  • slots
  • emit

reactive data가 아니므로 context는 destructure 가능. props는 불가능.

<script>
export default {
  props: {
    name: String,
    price: Number,
  },
  setup(props, { attrs, slots, emit}) {
    console.info('name', props.name)
    console.info('price', props.price)
  }
}
</script>

ref로 값을 전달하면 Vue는 value property를 가지는 object로 감싼다.

그래서 접근하거나 변형할 때 .value를 통한다. wrapper로 감싸면 반응성을 잃지 않고 안전하게 사용할 수 있다. script 외부에서는 unwrap한다.

아래 예제에서, name을 let으로 선언하고, .value를 통해 값을 바꿔도 반응성은 유지된다.

setup() {
  let name = ref("The Snazzy Burger");
  name.value = "Nice Burger"
  function placeOrder() {
    alert("Your order has been placed!");
  }
  const addItemToCart = (item) => {
    alert(`You added ${item} to your cart!`);
  };
  return { name, placeOrder, addItemToCart } ;
},

하지만 .value를 빼먹으면 값이 교체되서 반응성을 잃는다.

<template>
  <h1>{{name}}</h1>
  <input type="text" v-model="name">
</template>

<script>
import { ref } from "vue";

export default {
  setup() {
    let name = ref("The Snazzy Burger");
    name = "Nice Burger"
    return { name } ;
  },
}
</script>
image

ref

장점

  • primitive, non-primitive 둘 다 쓸 수 있음
  • destructuring하기 좋음
import { ref } from 'vue'
export default () => {
  return {
    name: ref('Pizza'),
    price: ref(1000),
  }
}

단점

  • .value를 쓰는 게 성가실 수 있다.
  • context에 따라 쓰는 방법이 달라서 헷갈린다.
    • template에선 name
    • setup에선 name.value
    • options api에선 this.name

reactive

장점

  • .value를 안 써도 됨
  • context가 달라도 문법이 똑같음
  • toRefs를 사용하면 destructuring이 가능하긴 함
    • toRefs => reactive object property를 돌면서 하나씩 ref로 변경해줌
import { reactive, toRefs } from 'vue'
export default () => {
  return toRefs(
    reactive({
      name: ref('Pizza'),
      price: ref(1000),
      time: ref(2000),
    })
  )
}

단점

  • primitive에 사용하지 못함
  • reassign을 하면 반응성을 잃음
  • 전체 object를 교체하지 못함.
let posts = reactive(['post 1', 'post 2'])
posts = ['post 3', 'post 4']

computed

  • getter, setter 선언이 가능
  • .value를 사용해야 함
const pricePretty = computed(() => `$${props.price.toFixed(2)}`)
const pricePrettySentence = computed(() => `Price: ${pricePretty.value}`)

watch

options api처럼, immediate, deep option이 가능

watch(
  name,
  (newName, oldName) => {
    console.log(`Name changed from ${oldName} to ${newName}`)
  },
  {
    immediate: true,
    deep: true,
  }
)

의견

이상 vue school 강의를 듣고 요약한 내용이다. 아무래도 vue core member들이 강의한 내용이다 보니 이해도 잘 되고, 일반 블로그 글들에선 볼 수 없었던 관점 등을 배울 수 있었다.

경험이 쌓여서 ref와 reactive 중 어느 것을 선호할 수 있는 정도가 되고 싶다. options api의 코드 재사용성은 정말 안 좋았는데, composition api로 많이 개선됐으면 한다. 이것도 많이 써보면서 사례들을 경험해나가고 싶다.


Written by@Donghoon Song
사람들의 꿈을 이어주는 코멘토에서 일하고 있습니다.

InstagramGitHubTwitterLinkedIn