Options API vs Composition API
Options API 방식
이전까지 컴포넌트 작성 방법 (= 옵션 API (Option API))
data, methods, computed, watch와 같은 `옵션`들을 작성
- 컴포넌트 연산(`calc`) 기능과 이름(`name`)을 처리하는 두 가지 기능을 가진 컴포넌트
- 연산과 관련된 기능이 여러 옵션에 흩어져 있음
여러 기능을 가진 컴포넌트의 경우, 매우 복잡한 코드를 분석하기에는 불편한 방식
Composition API 방식
대규모 vue 애플리케이션에서 컴포넌트의 로직을 효과적으로 구성 & 재사용할 수 있도록 만든 함수 기반 API
위 Option API를 사용한 컴포넌트 방식과 달리 데이터, 메서드, 생명주기 메서드들이 관심 기능 별로 묶여있음
👉 특정 기능의 코드를 분석하고 작성하는 데 여러 행을 건너뛰면서 작업하지 않아도 됨
📌 Composition API는 기존 옵션 API의 컴포넌트 구조를 개선하고 컴포넌트 로직의 재사용성을 높일 수 있도록 설계됨
setup() 메서드를 이용한 초기화
기존의 data, methods, computed 옵션이 사라지고,
초기화 작업을 수행하는 `setup()` 옵션 메서드를 이용해 컴포넌트의 상태를 초기화 함
beforeCreate, created 단계에서 setup() 메서드가 호출됨
반응성을 가진 상태 데이터, 계산된 속성, 메서드, 생명주기 훅을 작성
- setup 내부에서 ref 함수를 이용해 두 개의 반응성을 가진 데이터 `x`,`y` 만듦
- `x`, `y` 값을 템플릿에서 이용할 수 있도록 `객체 형태`로 리턴
- 리턴된 `x`, `y`를 템플릿에서 v-model 바인딩으로 사용 (`{{x}}` 형식인 보간법도 됨)
반응성을 가진 상태 데이터
데이터의 변경을 자동으로 감지하고, 이에 따라 관련된 부분을 업데이트 하는 특성
데이터의 상태를 관리하고, UI를 동적으로 업데이트하는 데 도움을 줌
setup() 메서드 내에서는 `ref`와 `reactive`를 사용해 만듦
1) ref
reference의 약자, 기본 타입의 값을 이용해 반응성을 가진 참조형 데이터를 생성할 때 사용
Options API에서 data 옵션에 해당
해당 데이터를 스크립트에서 사용할 때 x.value로 접근해야함
왜??????????
`.value`를 사용하지 않고 바로 값을 대입해 버리면 반응성을 잃어버림
반응성을 잃어버린다 = 추후 값을 변경해도 화면 갱신 안 됨
2) reactive
`배열`, `객체` 등 참조형에 대한 반응성을 가지도록 함
- `x`, `y`, `result`를 포함한 객체를 반응성을 가지도록 `reactive()` 활용
- state 객체를 리턴하여 template에서 `state.xxx` 로 바인딩 함
📌 만일 객체나 배열을 ref () 를 이용해서 반응성을 갖도록 하고 싶은 경우,
state.value.x 와 같이 .value 속성을 사용해서 접근해야 함.\
computed()
옵션 API에서 computed 옵션에 해당 (계산된 속성)
Composition API도 마찬가지로 계산형 속성을 만들 때 사용
기존의 `이벤트`와 `calcAdd 메서드`를 이용해 result 값을 갱신하는 코드를 `computed()` 속성을 사용하여 변경
위와 같이 작성하는 경우 버튼을 클릭하지 않고 텍스트 박스에 값을 입력하면 즉시 결과가 바인딩 됨
📌 computed()에 의해 생성된 계산된 속성은 템플릿에서는 직접 이용 가능
watch & watchEffect
기존 옵션 API에서 watch 옵션을 이용해 감시자 기능을 제공
watch 옵션은 데이터, 속성 그리고 계산된 속성의 값이 변경되면 반응하는 기능 정의
watch 옵션을 통해 변경 전, 후의 값을 모두 확인 & 이용 가능
마찬가지로 Composition API 에서도 watch 함수를 통해서 동일한 기능으로 제공
watch
watch() 함수를 통해 제공
형식
watch(data, (current, old) => {
// 처리하려는 연산 로직
})
- `x` (첫 번째 인자): 감시하려는 대상 반응성 데이터, 속성, 계산된 속성
- handler(두 번째 인자): 핸들러 함수
- `current`: 변경된 값
- `old`: 변경되기 전 값
감시하려는 대상 (x)가 ref()를 이용해 만든 반응성 데이터라 할지라도,
`current`와 `old`는 ref 객체가 아닌 ref.value에 해당하는 값이므로, `.value` 속성을 통해 접근하지 않아도 됨
`reactive`를 이용해 생성한 반응성 객체에 대한 감시자를 설정하는 경우
감시대상에 대한 명확한 지정이 필요함
왜 명확하게 지정해야 하는데❓
명확하게 지정하지 않으면 handler 함수가 불필요하게 여러번 호출 됨
setup() {
name: 'Calc8',
setup() {
const state = reactive({x:0, result:0});
watch(state, (current, old) => {
state.result = current.x * 2;
})
return { state };
}
- reactive를 사용해 반응성 데이터 객체 `state` 생성
- state 내부의 값이 변경되면 핸들러 함수 실행하는 watch 작성
위와 같이 작성하면, x의 값이 변경되어 result가 바뀌면, result도 state 내부의 값이므로 핸들러 함수가 한 번 더 호출
그러면 state 내부의 x 값을 감시 대상으로 지정하면 어떨까?
setup() {
name: 'Calc8',
setup() {
const state = reactive({x:0, result:0});
watch(state.x, (current, old) => {
state.result = current.x * 2;
})
return { state };
}
위와 같이 state.x 로 설정한 경우, 에러 발생
왜냐하면, 감시 대상이 되는 데이터는 반응성을 가진 데이터여야 함
이 코드에서 반응성을 가진 데이터는 state임.
reactive로 생성한 반응성 데이터 객체 내부의 값을 감시 대상으로 하려면 getter 함수로 정의 하면 됨
setup() {
name: 'Calc8',
setup() {
const state = reactive({x:0, result:0});
watch (() => state.x, current, old) => {
state.result = current.x * 2;
})
return { state };
}
위와 같이 작성하면 `getter 함수`가 리턴하는 값의 변경에 대해서만 감시 함
watchEffect
Vue3에서 반응성 데이터 의존성을 추적하는 기능을 제공하는 새로운 방법
명시적으로 감시할 데이터를 지정하지 않고, 반응형 상태가 사용된 모든 곳을 자동으로 추적
- 반응형 데이터의 변화를 자동으로 감지
- 함수 내에서 사용되는 모든 반응형 데이터 변화 추적
형식
watchEffect(() => {
// 반응성 데이터를 사용하는 코드 작성
})
watch vs watchEffect
특성 | watch | watchEffect |
감시 대상 | 명시적으로 감시 데이터 지정 | 함수 내에서 사용된 모든 반응형 데이터 자동 추척 |
변화 처리 방식 | 이전 값, 새로운 값 비교하며 변화 시 콜백 실행 | 이전 값과 새로운 값 비교 X, 자동 실행 |
사용 목적 | 특정 데이터의 변화에 대해 구체적 작업 | 반응형 데이터의 변화 자동 추적, 부수적인 작업 처리 |
유용한 경우 | 비동기 작업, 데이터 변화에 따른 복잡한 로직 처리 | 간단한 로직 처리, 반응형 상태 초기화 또는 값의 변화 감지 |
호출 시점 | 변화가 발생할 때만 실행 | 반응형 상태가 변경될 때마다 자동 실행 |
생명주기 훅 (Life Cycle Hook)
Options API 생명주기 훅과의 차이점
- `beforeCreate`, `created` 메서드의 기능을 setup()으로 대체
- 나머지 생명주기 메서드는 앞에 `on` 접두어를 붙인 함수로 바뀜
- 실행할 함수를 매개변수로 전달
mounted 메서드 변경 예시
setup(){
// mounted
onMounted(() =>{
...
});
}
<script setup> 사용
단일 파일 컴포넌트 내부에서 Composition API를 편리한 문법적 작성 기능 제공
장점
- 적은 상용구 코드 사용 -> 간결한 코드 작성
- 순수 타입스크리트 언어를 사용해 props, 이벤트 선언
- 런타임 성능 더 좋음
- IDE에서의 타입 추론 성능이 더 뛰어남
기존 setup () 와의 차이
특성 | setup() | script setup |
구문 | `setup()` 함수 내에서 명시적 정의 | setup 생략, `<script setup>` 구문 사용 |
템플릿과의 연결 | 명시적으로 return으로 연결 | 자동으로 템플릿과 연결 |
return 사용 여부 | return을 사용하여 템플릿과 연결 | return 없이 자동 연결 |
사용법 | `setup ()` 함수 내에서 데이터 및 메서드 정의 | 간결하게 데이터 및 메서드 정의 |
컴포넌트 로직 작성의 간결함 | 상대적으로 긴 코드 | 간결하고 직관적인 코드 |
- setup()
함수 내부에서 반응형 데이터 & 메서드 정의
return으로 템플릿에 데이터 제공
<script setup>
setup 함수 자체 생략
자동으로 데이터와 메서드를 템플릿에 제공
컴포넌트 등록시 기존 `component:{}` 옵션 생략, import만 하면 바로 템플릿에서 사용 가능