본문으로 바로가기

[Vue] Vue2 에 Composition API 적용하기

category Helloworld!/Vue 2024. 1. 17. 14:04

Composition API 설치

  • install
npm install @nuxtjs/composition-api --save
buildModules: [
    ...
    '@nuxtjs/composition-api/module'
  ],

Composition API 사용 하기

  • Composition API import
import {reactive, ref} from "@nuxtjs/composition-api";
  • setup()에 전달된 인자에 대한 타입을 추론하려면, defineComponent 를 사용해야한다. #
<script lang="ts">
export default defineComponent({
  name: 'HomePage',
  components: {
    Logo,
  },
  setup() {
    const count: number = ref(0)
    return { count }
  }
})
</script>

Ref

  • setup 안에서 ref 를 출력할 땐 .value 를 붙여줘야한다.
let count = ref(0)
console.log(count.value)
  • 위 처럼 타입을 정의하지 않아도 알아서 타입을 체크하지만, ref 에 타입을 정의하고 싶다면 다음과 같이 두가지 방법이 있다
    첫번째 방법은 여러 타입을 정의할 때 사용하고, 두번째 방법은 기존에 지정 했던 타입을 재정의 할 때 사용하길 권장한다. #
const count: Ref<number | string> = ref('0') // 또는
const count = ref<number | string>(0)

Reactive

  • ref 와 달리 reactive 는 중첩된 타입을 가지 않는것을 권장한다. #
    그래서 그런지 위와 같이 여러 타입 정의할 수 있도록 도와주는 interface 가 존재하지 않는다. 😒
  • 출력은 ref 와 다르게 .value 없이 사용한다.
const header = reactive<IHeader>({ title: 'hello idus', useLogo: false }) // 또는
const header: IHeader = reactive({ title: 'hello idus', useLogo: false })
console.log(header.title)

Computed

  • get 만 할 경우
const handleClickInclude = () => count.value++
const handleClickExclude = () => count.value--
  • get, set 모두 사용할 경우
const computedText = computed({
    get: (): string => text.value,
    set: (newText): string => text.value = newText
})
  • 타입을 지정하고 싶으면 다음과 같이 사용하면 된다.
const computedText = computed<string>({
    get: (): string => text.value,
    set: (newText): number => text.value = newText
})

// 여러 타입 정의 시 ComputedRef 사용한다.
const style: ComputedRef<IBgStyle | undefined> = computed(() => {
  if (props.backgroundColor) {
    return {
      backgroundColor: props.backgroundColor,
    }
  }
})
  • 타입 지정할 때 볼 수 있듯이 computed  setup 안에서 사용할 땐 ref 처럼 .value 를 붙여줘야한다.
console.log(computedText.value)

Function

  • 모두가 아는 그것. 설명을 생략하겠다.
  • 아! 😮 ref, reactive, computed, function 등 모두 template 에서 사용하려면 return 을 해줘야한다.
setup() {
  const count = ref(0)

  const handleClickInclude = () => count.value++
  const handleClickExclude = () => count.value--

  return {
    count,
    handleClickInclude,
    handleClickExclude
  }
}
  • 위 코드는 간단하지만 코드가 길어지면 Composition API 사용하는데 의미가 없다. #

Watch

  • 한개의 소스만 Watch 할 경우, ref 일 경우와 아닐 경우 사용 방법이 다르다. #
// ref watch 할 경우
const count = ref(0)
watch(count, (count, prevCount) => {
  ...
})

// reactive, props (getter) 등을 watch 할 경우
const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
  ...
  }
)
  • 여러 소스를 Watch 할 경우는 다음과 같이 사용한다.
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  ...
})

Props

  • 자식 Component 에서 Props 을 선언할 땐 다음과 같이 defineComponent 안에 setup 보다 위에 선언한다.
  • 기존과 다른점이라면 Array 나 Object 에 as PropType<YourInterface> 를 사용해 타입을 지정할 수 있다는 것이다.
export default defineComponent({
  name: 'ProductList',
  props: {
    products: {
      type: Array as PropType<IProduct[]>, // Array 에 타입 정의
      required: true
    },
    order: {
      type: String,
      required: true
    }
  },
  setup() {
    ...
  }
})
  • setup 은 2가지의 인자를 전달하는데 props  context 이다. 따라서 자식 Component 에서 Props 로 받은 데이터를 setup 안에서 사용하고 싶다면 다음과 같이 사용하면 된다.
export default defineComponent({
  name: 'ProductList',
  ...
  setup(props) {
    return {
      ...useOrderedProduct(props),
      ...useOrderClasses(props)
    }
  }
})
  • Props 의 타입은 defineComponent 가 알아서 찾아주니 선언할 필요는 없다고 한다 #

 

Emit

  • setup 전달인자 중 context 안에 있는 emit 을 활용한다.
setup(props: ICommonButtonProps, { emit }: SetupContext) {
  ...

  const handleClickButton = () => {
    emit('click')
  }

  return {
    classes,
    style,
    handleClickButton
  }
}

Lifecycle Hooks

  • 이전 스터디때 설명 드렸던 바와 같이 beaforCreate, created hook을 setup 훅으로 대체하여 사용되고, 그 외 기존과 다르게 다음과 같이 Lifecycle이 달라지고 사용할 땐 앞에 on을 붙여서 사용 한다.
setup() {
  onMounted(() => {
    console.log('mounted!')
  })
  onUpdated(() => {
    console.log('updated!')
  })
  onUnmounted(() => {
    console.log('unmounted!')
  })
}

Template reference

  • Composition API를 사용하면, reactive refs API와 template 의 refs의 개념이 통합됩니다. templateref 를 사용하고 싶다면 기존과 같이 ref를 선언하고 setup에서 반환하면 된다.
<template>
  <div class="ProductList" ref="root">
    ...
  </div>
</template>

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

  export default {
    setup() {
      const root = ref(null)

    onMounted(() => {
      console.log(root.value) // <div class="ProductList">...
    })

    return {
      root
    }
  }
</script>