[FE][Vue] Composition API와 Composable

Choise.o·4일 전

FE

목록 보기
7/7
post-thumbnail

FE 프로젝트 버전 업그레이드 작업을 대비하기 위한 두번째 글
(첫번째는 Vite)

Vue2 와 Vue3 의 차이점이 뭘까

현재 Vue 2.7 + Composition API를 사용하는 중이라 개발할 때 크게 체감하는 부분은 없을 것 같다.
다만 Vue3의 코어 개념 한 가지를 꼽아보자면 역시 Composable 아닐까


Vue2 는 Vue3 로 넘어가면서 Options API를 버리고(...) Composition API 를 선택했다.
Vue는 “왜 굳이 Composition API를 만들었을까?”

결론부터 말하면
컴포넌트가 커질수록 로직이 찢어져 관리가 불가능해졌기 때문이다.

Vue3 설계 철학과 Composable을 정확하게 이해해보자.


1. Composable이란 무엇인가?

Composable은 Composition API로 만든 로직 재사용 함수이다.

일반적으로 useXxx 형태의 이름을 가진다.

// useCounter.ts
export function useCounter() {
  const count = ref(0);

  function increase() {
    count.value++;
  }

  return { count, increase }
}

컴포넌트에서는 이렇게 사용한다.

// Count.vue
setup() {
  const { count, increase } = useCounter();
  return { count, increase }
}

겉보기에는 단순한 함수처럼 보이지만, 일반 유틸 함수와 중요한 차이가 있다.

2. Composable vs 일반 Util function

구분Composable일반 유틸 함수 (Util Function)
목적Vue 로직 재사용순수 기능 재사용
Vue 의존성Vue Composition API 사용 (ref, watch 등)Vue와 관련 없음
상태(State)반응형 상태 보유 가능상태 보유하지 않음 (보통 stateless)
반응성(Reactivity)reactive / ref 자동 추적없음
생명주기 연동컴포넌트 lifecycle과 함께 동작lifecycle 개념 없음
컴포넌트와 관계컴포넌트의 일부처럼 동작완전히 독립적
실행 시점setup() 내부에서 사용어디서든 호출 가능
상태 공유가능 (파일 상단 ref 사용 시)기본적으로 불가능
주 사용 용도UI 로직, 데이터 흐름, 상태 관리계산, 포맷팅, 변환
예시useSearch(), useAuth()formatDate(), sum()
테스트 방식Vue 환경 고려 필요순수 함수 테스트 가능
구조적 역할아키텍처 구성 요소단순 헬퍼 함수
  • 예시
// Composable
export function useCounter() {
  const count = ref(0);

  function increase() {
    count.value++;
  }

  return { count, increase }
}

// Util function
export function sum(a: number, b: number) {
  return a + b;
}

Composable은 Vue 반응형시스템 위에서 동작하는 상태를 가진 로직 모듈이고,
Utility Function은 프레임워크와 무관한 순수 기능 함수이다.


3. Composable 등장 배경

3-1) Option API

Vue2의 Options API는 구조적으로 이런 형태였다.

export default {
  data() {},
  methods: {},
  computed: {},
  watch: {}
}

이러한 구조는 기능 단위가 아니라 옵션 단위로 코드가 나뉜다는 문제점이 있다.

ex) "검색 기능"이라는 단일 기능에 대해 연관된 상태, 동작, 반응형 동작(computed, watch)이 한 곳에 모여있는게 아니라 여러 곳에 흩어져 작성된다.

// 다 같은 검색 기능인데 흩어져 작성된다
 ├ data
 ├ watch
 ├ methods
 └ mounted

이런 기능들이 하나의 컴포넌트에 여러개있다면?🥴

컴포넌트가 커질수록 로직은 파편화되고
Vue 팀은 이 문제를 Logic Fragmentation이라고 설명한다.

3-2) Composition API

Composition API는 코드를 기능 기준으로 묶는다.

setup() {
  const search = useSearch();
}

// 검색 기능과 관련된 것들은 아래 함수 하나에 묶인다useSearch()

Options APIComposition API
분리 기준옵션(data, methods 등) 기준 분리기능(로직) 기준 분리
컴포넌트 규모로직이 모이며 비대해짐로직이 분리되어 가벼움
재사용 전략mixincomposable

Vue는 로직 파편화 문제를 해결하기 위해 Composition API 를 선택했고 이 과정에서 composable이 등장했다.


4. Composable 은 함수형 프로그래밍일까

Composition API는 함수 기반 구조라서 함수형 프로그래밍처럼 보인다.
하지만 Vue 공식 문서에는

Composition API는 함수형 프로그래밍이 아니다.

라고 명확하게 써져있다.

// Composition API (mutable)
const count = ref(0);

count.value++;   // 상태를 직접 변경


// 함수형 프로그래밍 (immutable)
const increment = count => count + 1;

const newCount = increment(count); // 새 값 생성 

Vue는 상태를 직접 변경한다.
이는 불변성을 강조하는 함수형 프로그래밍과 다르다.


5. Composable의 상태 관리

상태는 기본적으로 독립적이다

const a = useCounter();
const b = useCounter();

a와 b는 서로 다른 상태를 가진다.

상태를 공유하는 방법은 없을까? 있다.
모듈 스코프에 상태를 생성하면 공유 상태가 된다.

// useAuth.ts
const user = ref(null);

export function useAuth() {
  return { user }
}

useAuth()를 어디서 호출해도 user는 같은 ref 인스턴스를 가리킨다.
작은 범위의 전역 store처럼 동작한다.


Composable을 이해하고 보면

ue3에서 가장 체감되는 변화 중 하나(Composition API)는 단순히 새로운 문법이 아니라 로직을 분리하고 다시 구성하는 방식의 변화이다.

이전에는 .vue 파일 내부에 로직을 직접 작성했다면,
이제는 여러 composable을 조합하여 화면을 구성하는 조립 레이어(assembly layer)에 가까워졌다.

[정리]

  • Options API = 옵션 중심 구조
  • Composition API = 기능 중심 구조
  • Composable = 기능 단위 로직 모듈

나는 composable 조립 레이어로서 컴포넌트를 분리하고 있었는가🤔
반성하고 하나 또 배우며 마무리해본다.

참고

0개의 댓글