Composition-API

sooni·2023년 4월 27일
0

composition api 는 대규모 프로젝트에서도 코드의 재사용성을 증가와 로직에 대한 관심사를 모으기 위해 새롭게 추가된 API이다. namespace 충돌을 방지할 수 있고 코드 로직에 대한 관심사가 한군데에 집중되게 되어 가독성 면에서 큰 이점이 존재한다. 특히 코드의 재사용성과 타입 추론이 크게 개선되었다.

✨Composition-API 배경

기존의 vue2 버전에서는 직관적인 확인이 어렵고 재사용성이 떨어진다. 이러한 문제를 해결하기 위해 composition API를 사용한다.

기존 Vue 2

<template>
	<div>
        <h1>{{ countWithUnit }}</h1>
        <button @click="increase">Increase</button>
        <button @click="decrease">Decrease</button>
    </div>
</template>

<script>
export default {
    data() {
        return {
            count: 0
        }
    },
    computed: {
        countWithUnit() {
            return this.count + '입니다'
        }        
    },
    methods: {
        increase() {
            ++this.count
        },
        decrease() {
            --this.count
        }
    }
}
</script>
  • 같은 기능임에도 불구하고 data, computed, methods에 코드가 흩어져있다.

Composition-API 사용

<template>
	<div>
        <h1>{{ countWithUnit }}</h1>
        <button @click="increase">Increase</button>
        <button @click="decrease">Decrease</button>
    </div>
</template>

<script>
import { ref, computed } from '@vue/composition-api'

const useCount = () => {
    const count = ref(0)
    const countWithUnit = computed(() => count.value + '입니다')
    const increase = () => ++count.value
    const decrease = () => --count.value
    
   	return { countWithUnit, increase, decrease }
}

export default {
    setup() {
        const { countWithUnit, increase, decrease } = countWithUnit()
        
        return {
            countWithUnit,
            increase,
            decrease
        }
    }
}
</script>
  • count의 기능에 대한 값과 로직 값이 모두 useCount 함수 내에 모여있다.
  • React의 Hooks와 유사하다.
  • 목적에 맞는 코드를 모듈화하여 유연하고 확장이 가능하다.

📌 #1. LifeCycle

기존 Vue2

<script>
export default {
	mounted() {
        
    },
    updated() {
        
    },
    destroyed() {
        
    },
}
</script>

Composition-API

<script>
import {
    onMounted,
    onUpdated,
    onUnmounted
} from '@vue/composition-api

const funcion1 = () => {
    onMounted(() => {
        // mounted1
    })
}

const funcion2 = () => {
    onMounted(() => {
        // mounted2
    })
}
    
export default {
    setup() {
        function1()	// mounted1
        function2()	// mounted2
        
        onUpdated(() => {
            // updated
        })
        
        destroyed(() => {
            // unmounted (destroyed)
        })
    }
}
</script>
  • 기존에는 컴포넌트당 하나의 생명주기 훅을 사용했지만, Composition-API를 사용할 경우 여러개를 사용할 수 있다.

LifeCycle

기존 Vue 2Composition-API
beforeCreatesetup
createdsetup
beforeMountonBeforeMount
mountedonMounted
beforeUpdatedonBeforeUpdated
updatedonUpdated
beforeDestroyedonBeforeUnmount
destroyedonUnmounted
errorCapturedonErrorCaptured

📌 #2. 반응형 데이터 (reactive, ref)

반응형 데이터는 값이 변경됨에 따라 이를 감지하고 해당 값에 종속된 작업(Side Effect)이 수행된다.

기존 Vue 2

data() 내부에 선언을 통해 반응형 데이터를 만든다.

<template>
	<div>
        {{ message }}        
    </div>
</template>

<script>
export default {
    data() {
        return {
            message: 'Hello World!!'
        }
    }
}

</script>

Composition-API

Composition-API의 경우, 2가지 유형(reactive, ref)으로 반응형 데이터를 만든다.

<script>
import { reactive, ref, computed } from '@vue/composition-api

export default {
    setup() {
        // 1. reactive
        const reactiveValue = reactive({ name: 'sooni'})
        reactiveVlaue.name	// sooni
        
        // 2. ref
        const refValue = ref(10)
        refValue.value	// 10
    }
}
</script>

reactive

  • 오직 객체만 받는다.
  • reactive는 인자로 받은 객체와 완전히 동일한 프록시 객체를 반환한다.
  • 원본 객체에 접근하는 것과 동일하게 값에 접근 가능하다.
  • reactive를 통해 생성된 객체는 모두 깊은(Deep) 감지를 수행한다.

ref

  • 모든 원시타입(Primitive) 값을 포함한 여러가지 타입의 값을 받는다.
  • value 속성을 통해 접근 및 변경할 수 있다.

ref 객체는 원본 값을 value라는 속성에 담아두고 변경을 감시하는 객체이며, reactive는 원본 객체 자체에 변경을 감지하는 옵저버를 추가하여 그대로 반환한 값이다.

isRef, toRefs

어떤 유형의 값인지 확인하기 위한 isRef, reactive 값을 ref 값으로 변환하는 toRefs가 존재한다.

isRef

ref값과 reactive값에 따라 다르게 처리해야 할 경우 사용한다.

<script>
import { reactive, ref, isRef } from '@vue/composition-api

export default {
    setup() {
        const reactiveValue = reactive({ name: 'sooni' })
        const refValue = ref(10)
        
        const printValue = obj => {
            console.log(isRef(obj) ? obj.value : obj)
        }
    }
}
</script>
  • ref 값의 경우 value 속성을 통해 데이터에 접근하므로 ref인 경우 obj.value를 출력하고, ref가 아닌 경우(reactive) obj를 그대로 출력하도록 구현된 모습이다.

toRefs

<script>
import { reactive, ref, isRef } from '@vue/composition-api

const useMousePoint = () => {
	const pos = reactive({ x: 0, y: 0 })
    return toRefs(pos)	// convert to ref
}

export default {
    setup() {
        const { x, y } = useMousePosition()
        
        return {
            x,
            y
        }
    }
}
</script>
  • useMousePoint에 있는 pos 객체의 각각의 값을 사용하고 싶은 경우, reactive를 toRefs를 통해 ref 값으로 변환한다.

📌 #3. Computed

<template>
	<div>
        <h1>{{ value2x }}</h1>
    </div>
</template>

<script>
import { ref, computed } from '@vue/composition-api'

export default {
    setup() {
        const myValue = ref(10)
        const value2x = computed(() => myValue * 2)
        
        return {
            value2x
        }
    }
}
</script>
  • getter 함수가 반환하는 값에 대해 변경 불가능한 반응형 데이터를 반환한다.

참고

0개의 댓글