Vue.js 3 Composition API

Kyu·2020년 3월 24일
3
post-thumbnail

Vue.js 3 진행상황

암스테르담 Vue.js 컨퍼런스에서 1Q 말에 출시할 예정이고, 2Q 말에 최종 버전을 발표할 예정이라고 발표했습니다.

중요한 변경 사항

  • Composition API
  • Portals
  • Fragments
  • v-model API
  • Suspense
  • Typescript 지원

Vue.js Conference - Amsterdam 2020

Composition API (현재 v0.5.0)

Vue.js 3에 도입되는 컴포넌트 로직을 유연하게 구성할 수 있는 API 모음입니다.
기존의 Options API를 사용하여 여러 혼재된 논리 구조를 분리하고 재사용 가능하게 하는것이 목적입니다.
Untitled 1

We acknowledge the creativity of React Hooks, and it is a major source of inspiration for this proposal. (우리는 React Hooks의 창의성을 인정하며, 이 제안의 주요 영감원이다.)

기본 예제

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
</script>

Reactive State와 Side Effects

반응형 상태와 부수효과를 만드는 방법입니다.
watchEffect는 함수를 즉시 실행하고, 사용한 모든 반응 상태 속성을 종속성으로 추가하여 추적합니다.
state.count가 변경되면 내부 함수가 다시 실행됩니다.

import { reactive, watchEffect } from 'vue'

const state = reactive({
  count: 0
})

watchEffect(() => {
  document.body.innerHTML = `count is ${state.count}`
})

reactive는 Vue 2.x API에 있는 Vue.observable()과 동일합니다.

computed

computed로 다른 상태에 의존하는 계산된 속성을 만들 수 있습니다.
다만 reactive와 다르게 computedref를 사용하기 때문에, .value를 통해 값을 접근해야 합니다.

const double = computed(() => state.count * 2)

watchEffect(() => {
  console.log(double.value)
}) // -> 0

state.count++ // -> 2

ref

ref는 primitive type을 가변 참조 객체로 만들고, 내부 값을 가리키는 단일 속성 value가 있습니다.

import { ref, watch } from 'vue'

const count = ref(0)

function increment() {
  count.value++
}

reactive

reactive는 객체를 반응형으로 만듭니다.

import { reactive } from 'vue'

const state = reactive({
  count: 0
})

function increment() {
  state.count++
}

객체를 사용하는 경우 reactive를 사용하면 되지만, 반환된 객체에 대한 참조유지를 위해 객체를 해제하거나 펼치는 경우 toRefs()를 사용합니다.

const state = reactive({
  count: 0
})

const { count } = state // 반응성 손실, 값 변경시 재렌더링 동작 안함.
const state = reactive({
  count: 0
})

const stateAsRefs = toRefs(state);

const { count } = stateAsRefs // 반응성 유지
/*
Type of stateAsRefs:
{
  count: Ref<number>,
}
*/

컴포넌트내에서 사용하기

기본적으로 Composition API는 컴포넌트 컨텍스트 외부에서 사용할수 있고, 컴포넌트 인스턴스에서 사용할 수도 있습니다. 컴포넌트 내부에서는 setup() 함수에서 초기화 부분을 선언합니다. setup() 함수는 beforeCreate 이전에 호출됩니다.

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
</script>

Lifecycle Hooks

상태 변화에 따라 부수효과를 적용하는 것은 watchEffectwatch API를 사용하고, 기존의 라이프 사이클 훅은 onXXX API 형태로 사용할 수 있습니다.

  • beforeCreate -> use setup()
  • created -> use setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

새로 추가된 항목

  • onRenderTracked
  • onRenderTriggered

논리 추출 및 재사용

중복되는 논리를 추출하여 재사용 가능하도록 만들 수 있습니다.
Counter 애플리케이션을 작성하는 경우, 증감 부분을 분리하여 재사용 할 수 있습니다.

/* use ref */
export function useCount() {
  const count = ref(0);
  const increment = () => ++count.value;
  const decrement = () => --count.value;

  return { count, increment, decrement };
}

/* use reactive */
export function useCount() {
  const stateAsRefs = reactive({ count: 0 });
  const increment = () => ++stateAsRefs.count;
  const decrement = () => --stateAsRefs.count;
  const { count } = toRefs(stateAsRefs);

  return { count, increment, decrement };
}
<template>
  <div>
    <h3>Number is: {{ count }}</h3>
    <button class="myButton" @click="increment">Increment</button>
    <button class="myButton" @click="decrement">Decrement</button>
  </div>
</template>

<script>
import { useCount } from "@/hooks/useCount";

export default {
  setup() {
    const { count, increment, decrement } = useCount();
    return {
      count,
      increment,
      decrement
    };
  }
};
</script>

재사용 로직을 분리하여 모아놓은 vue-hooks를 사용할 수도 있습니다.

참고

리액트와 비교

암스테르담 2020

Vue3 소개

0개의 댓글