Vue3 ) TodoApp 을 통한 OptionsAPI 와 Composition API 비교
같은 동작을 하는 TodoApp 을 각각 OptionsAPI 와 Composition API 를 이용해 제작했습니다.
전체 코드는 아래 링크를 통해 Github 에서 확인하실 수 있습니다.
README 파일을 참고해 브랜치별로 원하는 코드를 볼 수 있습니다.
실행화면
코드 비교
setup 사용
Options APi
<!-- template -->>
<TodoInput v-model="todoText" @add="addTodoItem"></TodoInput>
<!-- script -->
<script lang="ts">
export default {
data() {
return {
todoText: "" as string,
};
},
methods:{
initTodoText() {
this.todoText = "";
},
}
}
</script>
Composition API
<!-- template -->>
<TodoInput v-model="state.todoText" @add="addTodoItem"></TodoInput>
<!-- script -->
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
setup() {
// options API 에서의 data 속성과 동일함
const state = reactive({
todoText: "" as string,
});
// options API 에서의 methods
const initTodoText = () => {
state.todoText = "";
};
return { state, initTodoText };
}
})
</script>
- Options API 와 다르게 Composition API 에서는 setup() 함수 내부에 data 속성과 method, lifeCycle hook, watch 를 입력합니다.
그 다음 setup() 함수내에서 생성한 함수들을 return 해주어야 해당 함수들을 사용할 수 있습니다. - 또한 setup() 함수 내에서는 this 의 사용이 불가능합니다.
- 위 예시에서 state 함수 내에서 data 속성을 정의했기 때문에 data 속성은
state.todoText
로 data 를 가져올 수 있습니다. - defineContent 는 TypeScript 적용을 위해 사용했습니다.
Props
props 를 사용하는 방법에 있어서도 차이가 있습니다.
Options API
- App.vue
<!-- template -->
<TodoListItem
v-for="(todoItem, index) in todoItems"
:key="index"
:index="index"
:todoItem="todoItem"
></TodoListItem>
<!-- script -->
<script lang="ts">
import TodoListItem from "./components/TodoListItem.vue";
// 생략
data() {
return {
todoItems: [] as Todo[],
};
},
</script>
- TodoListItem.vue
<!-- template -->
<span class="item"@click="toggleItem">{{
todoItem.title
}}</span>
<!-- script -->
<script lang="ts">
props: {
todoItem: Object as PropType<Todo>,
index: Number,
},
methods:{
checkProps(){
console.log(this.todoItem);
}
}
</script>
Composition API
- App.vue
<!-- template -->
<TodoListItem
v-for="(todoItem, index) in state.todoItems"
:key="index"
:index="index"
:todoItem="todoItem"
></TodoListItem>
<!-- script -->
<script lang="ts">
import TodoListItem from "./components/TodoListItem.vue";
// 생략
setup() {
const state = reactive({
todoItems: [] as Todo[],
});
return { state };
}
</script>
- TodoListItem.vue
<!-- template -->
<span class="item" @click="toggleItem">{{
todoItem.title
}}</span>
<!-- script -->
<script lang="ts">
props: {
todoItem: Object,
index: Number,
},
setup(props, context) {
const checkProps = () => {
console.log(props.todoItem);
};
return { removeItem };
}
</script>
Vue2 버전에서부터 사용하던 Options API 에서는 상위 컴포넌트에서 내려받은 props 에 this 를 사용해 접근했습니다.
하지만 위에서 언급한것처럼 Composition API 의 setup() 내부에서는 this 사용이 불가능합니다.
따라서 setup() 의 props 인자를 이용해 this 가 아닌 props
키워드를 이용해 props 에 접근할 수 있습니다.
이는 this 의 무분별한 사용을 막게 해줍니다.
Emit 이벤트
Options API
- App.vue
<!-- template -->
<TodoListItem
v-for="(todoItem, index) in todoItems"
:key="index"
@remove="removeTodoItem"
@toggle="toggleTodoItem"
></TodoListItem>
<!-- script -->
<script lang="ts">
import TodoListItem from "./components/TodoListItem.vue";
// 생략
methods:{
removeTodoItem(index: number) {
this.todoItems.splice(index, 1);
},
}
</script>
- TodoListItem.vue
<!-- template -->
<button type="button" @click="removeItem">삭제</button>
<!-- script -->
<script lang="ts">
methods: {
removeItem() {
this.$emit("remove", this.index);
},
}
</script>
Composition API
- App.vue
<!-- template -->
<TodoListItem
v-for="(todoItem, index) in state.todoItems"
:key="index"
@remove="removeTodoItem"
@toggle="toggleTodoItem"
></TodoListItem>
<!-- script -->
<script lang="ts">
import TodoListItem from "./components/TodoListItem.vue";
// 생략
setup(){
const removeTodoItem = (index: number) => {
state.todoItems.splice(index, 1);
};
return { removeTodoItem };
}
</script>
- TodoListItem.vue
<!-- template -->
<button type="button" @click="removeItem">삭제</button>
<!-- script -->
<script lang="ts">
setup(props, context) {
const removeItem = () => {
context.emit("remove", props.index);
};
return { removeItem };
}
</script>
Options API 에서는 this.$emit
을 이용해 상위 컴포넌트로 이벤트를 전달 할 수 있었습니다.
Composition API 에서는 setup() 내부에서 this
사용이 불가능합니다.
따라서 setup() 함수의 두 번째 인자인 context 를 이용해context.emit()
와 같이 emit 을 사용할 수 있습니다.
computed 사용법
할 일의 상태 변경을 위한 클래스 바인딩을 예시로 들겠습니다.
Options API
<!-- template -->
<span :class="todoItemClass" @click="toggleItem">{{
todoItem.title
}}</span>
<!-- script -->
<script lang="ts">
computed: {
// style 조건
todoItemClass(): string | null {
return this.todoItem.done ? "complete" : null;
},
},
</script>
Composition API
<!-- template -->
<span :class="todoItemClass" @click="toggleItem">{{
todoItem.title
}}</span>
<!-- script -->
<script lang="ts">
import { computed } from "vue";
setup(){
const todoItemClass = computed(() => {
return props.todoItem.done ? "complete" : null;
});
return { todoItemClass };
}
</script>
Options API 에서는 computed: {}
를 이용해 함수를 바로 정의할 수 있었습니다.
하지만 Composition API 에서는 computed 속성을 import 한 뒤,
함수표현식을 통해 computed 를 선언합니다.
그리고 마찬가지로 해당 함수를 return 해주어야 사용할 수 있습니다.
created => X
Options API 와 Composition API 의 라이프사이클 훅은 차이가 있습니다.
다음은 페이지 진입 시 바로 목록을 조회하기 위한 코드입니다.
Options API
created() {
this.fetchTodoItems();
},
Composition API
setup(){
fetchTodoItems();
}
Options API 의 라이프사이클 훅엥서 사용되는 beforeCreate, created 는 Composition API 의 라이프사이클 훅에서는 필요가 없습니다.
setup 은 beforeCreate 와 created 훅 사이에 실행되는 시점이기 때문에 두 가지 훅은 정의할 필요가 없습니다.
( setup 직전에 beforeCreate(), setup 직후에 created() )
Options API 와 Composition API 두 가지 방법 모두 저의 코딩스타일로 진행했기 때문에 보시는 분들마다 차이가 있을거라 생각합니다.
비효율적인 코드가 있었다거나, 바람직하지 못한 방법으로 작성한 코드를 발견하셨다면 언제든지 댓글로 알려주시면 감사하겠습니다.
간단한 TodoApp 을 두 가지 방법으로 만들어보면서 Options API 와 Composition API 의 차이를 조금 더 이해할 수 있었던 것 같습니다.
'Study > Vue' 카테고리의 다른 글
VueJS 3 ) Composition API 를 기반으로 한 NewsWebApp (0) | 2022.03.21 |
---|---|
VueJS 3 ) setup() 함수의 2 가지 인자 props, context (0) | 2022.03.20 |
Vuejs ) TodoApp (Vue2에서 Vue3으로) (0) | 2022.03.20 |
Chart.js ) Vue2 + Chart.js (0) | 2022.03.01 |
Vue 2 ) Vue 에서 fontAwesome Icon 사용하기 (0) | 2022.01.18 |
댓글