이번에 ssafy 내에서 진행할 프로젝트에서 Vue3을 이용한 프론트엔드 제작에 나섰다.
Vue는 2.x 버전만 공부해봤던 차라, 이번 기회에 Vue3도 공부를 해보고자 한다.
그 중 가장 큰 차이라고 생각하는 Composition api를 학습한 내용을 정리하려고 한다.
저번 웹 프로젝트에서 Vue2를 사용해 개발을 하던 도중 생각보다 component가 점점 많아지고, 생각하던 구조에서 조금씩 벗어나서 코드가 조금 지저분해졌던 경우가 있다.
내가 A 컴포넌트에서 사용했던 메소드가 B에서 필요해지기도 하고, 또 computed와 data를 위 아래로 왔다갔다 하다보니 점점 헷갈리기도 했다.
즉, 하나의 컴포넌트에서 여러가지 일들이 진행되게 되는데, 대부분의 경우 컴포넌트의 옵션들(data
, computed
, methods
, watch
)로 논리가 구성된다. 점차 컴포넌트가 커지면 이러한 논리들이 분리가 되면서 논리 내부의 코드의 역할들이 많아진다. 그 결과 이리저리 Jump 해가면서 논리구조를 파악해야하는 과정이 생긴다.
아래의 사진을 보자.
왼쪽 컴포넌트는 Options Api를 사용했고, 오른쪽은 Composition Api를 사용했다. Options Api를 보면 컴포넌트 상의 같은 논리로 이루어져야하는 메소드들이 모두 분리가 되어있고, 이 분리는 근본적으로 논리적 관심사를 애매하게 만든다. 하나의 로직에 대해 작업할 때, 관련 코드를 위로갔다 아래로 갔다 해야하는 불편함이 생긴것이다.
결국 이렇게 되니, 하나의 로직 단위로 개발을 하려해도 이 옵션의 규칙을 지켜야하고 더 많은 로직이 추가될 수록 코드의 양이 많아져 가독성이 떨어지고 유지보수성이 낮아진다.
그렇게, 동일한 로직과 그 관련 코드를 함께 배치하여 가독성이 좋게 만든 것이 Composition API다.
Composition API 작업을 시작하기 위해서는 실제로 사용할 수 있는 장소가 필요한데 그 곳이 바로 Setup()이다.
새로운 setup 컴포넌트 옵션은 컴포넌트가 생성되기 전에, Props가 한번 resolved될 때 실행된다. 그게 composition API의 진입점 역할을 한다.
여기서 중요한 사실!!
setup이 실행될 때, 컴포넌트 인스턴스가 아직 생성되지 않아서 setup 옵션 내에 this가 존재하지 않는다. 즉, props를 제외하고, 컴포넌트 내에 다른 속성에 접근할 수 없다. Local state, computed, propperties, methods들.
setup에서 반환된 모든 것이 컴포넌트의 템플릿뿐만 아니라 나머지 컴포넌트(computed properties, methods, 라이프사이클 훅)에 노출된다.
Ref가 있는 반응성 변수
Vue3.0에서는 다음과 같이 ref 펑션을 사용하여 어디서나 변수를 반응성 있도록 만들 수 있다.
ref는 전달인자를 받고, 반응성 변수의 값에 접근하거나 변경할 수 있는 속성을 가진 객체를 반환한다.
import { ref } from 'vue'
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0
counter.value ++
console.log(counter.value) // 1
객체 안에 값을 감싸는 건 불필요할 수 있지만, JavaScript에서 다른 데이터 타입에 걸쳐 동작을 통일시켜야한다. JavaScript에서 원시타입은 참조에 의한 전달이 아니라 값에 의한 전달(pass by value)이기 때문이다.
그래서 모든 값을 감싸는 ref(), 즉 wrapper object를 가지고 있으면 어딘가에서 반응형을 잃어버릴 염려가 없다.
Options API와 비교하여 Composition API 형태를 만들기 위해 setup안에 라이프사이클 훅을 등록하는 방법도 필요한데, Vue에서 export할 수 있는 몇가지 function들이 있다.
import { onMounted } from 'vue'
setup (props) {
const function a = () => {
// sth
}
onMounted(a) // mounted에서 a 함수를 호출
}
watch옵션을 사용하면 컴포넌트 내부의 속성에 감시자를 설정하는 것과 같이 Vue에서 import한 watch function을 사용하여 작업을 수행할 수 있다.
import { ref, watch } from 'vue'
const conter = ref(0)
watch(counter, (newValue, oldValue) => {
console.log('새로운 값: ' + counter.value)
})
counter가 수정될 때마다 watch는 트리거하고 두번째 전달인자인 콜백을 실행해서 콘솔에 새로운 값을 나타낼 수 있다.
ref와 watch와 마찬가지로, computed 속성은 vue에서 import 한 computed function으로 Vue component외부에서도 computed속성을 사용할 수 있다.
import { ref, computed } from 'vue'
const counter = ref(0)
const twiceTheCounter = computed(() => counter.value * 2)
counter.value ++
console.log(counter.value) // 1
console.log(twiceTheCounter) // 2