본문 바로가기
Study/Vue

VueJS 3 ) TodoApp 을 통한 OptionsAPI 와 Composition API 비교

by JongIk 2022. 3. 20.
반응형

Vue3 ) TodoApp 을 통한 OptionsAPI 와 Composition API 비교

같은 동작을 하는 TodoApp 을 각각 OptionsAPI 와 Composition API 를 이용해 제작했습니다.

전체 코드는 아래 링크를 통해 Github 에서 확인하실 수 있습니다.

README 파일을 참고해 브랜치별로 원하는 코드를 볼 수 있습니다.

Github 로 이동

실행화면


코드 비교

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() )

참고자료 - Vue3 공식문서


Options API 와 Composition API 두 가지 방법 모두 저의 코딩스타일로 진행했기 때문에 보시는 분들마다 차이가 있을거라 생각합니다.

비효율적인 코드가 있었다거나, 바람직하지 못한 방법으로 작성한 코드를 발견하셨다면 언제든지 댓글로 알려주시면 감사하겠습니다.

간단한 TodoApp 을 두 가지 방법으로 만들어보면서 Options API 와 Composition API 의 차이를 조금 더 이해할 수 있었던 것 같습니다.

반응형

댓글