[Vue] 기본 문법

배창민·2025년 11월 20일
post-thumbnail

Vue 3 Composition API 기초 정리

CDN 으로 Vue를 불러와서 Composition API 중심으로 쓰는 기본 문법을 정리한 글이다.
(앱 생성 → 상태 관리 → 템플릿 → v-if / v-for → v-model → watch → 라이프사이클 순서)


1. Vue 앱 시작하기

1.1 앱 생성: createApp

Vue 앱은 createApp() 호출로 시작한다.

const app = createApp({
  setup() {
    // 반응형 상태 정의, 함수 정의
  }
});

setup() 안에서 ref, reactive, computed, watch 등을 사용한다.


1.2 DOM 연결: mount

실제 DOM 요소와 연결해야 화면에 렌더링된다.

<div id="app"></div>

<script>
  app.mount('#app');
</script>
  • mount 호출 전까지는 화면에 아무것도 그려지지 않는다
  • Vue 컴포넌트 라이프사이클이 시작되는 지점

1.3 반응형 상태: ref

단일 값을 반응형으로 만들 때 사용한다.
(숫자, 문자열, boolean, null, 배열 등)

const count = ref(0);

count.value++; // JS 코드에서는 .value 로 접근

특징

  • 템플릿 안에서는 {{ count }} 처럼 .value 없이 바로 사용
  • JS 코드에서는 count.value 로 읽고 쓴다
  • 값이 바뀌면 자동으로 렌더링이 갱신된다

1.4 반응형 상태: reactive

객체 전체를 반응형으로 만든다.

const user = reactive({
  name: '홍길동',
  age: 20
});

user.age++; // .value 없이 바로 속성 접근

1.5 ref vs reactive 비교

구분refreactive
상태 종류단일 값객체 전체
접근 방식.value 로 접근속성에 바로 접근
배열/객체저장 가능하지만 .value 필요본질이 객체라 더 자연스러움
  • 단순 숫자/문자열 → ref
  • 여러 필드를 가진 상태 → reactive

1.6 템플릿 보간: {{ }}

Mustache 문법으로 값을 출력한다.

<p>{{ message }}</p>
  • Vue가 자동으로 이스케이프 처리해서 일반 텍스트 출력에 안전하다

2. computed – 파생 데이터 계산

2.1 왜 computed 가 필요한가

템플릿 안에서 직접 계산식을 쓰면

  • 렌더링마다 동일 계산 반복
  • 연산 비용이 크면 성능 저하
  • 여러 곳에서 같은 계산을 반복하게 됨

→ 계산 결과를 파생 상태(derived state) 로 관리할 필요가 있다.

2.2 computed 기본 사용

const price = ref(1000);
const quantity = ref(2);

const total = computed(() => price.value * quantity.value);
  • 의존하는 값(price, quantity)이 바뀔 때만 다시 계산
  • 결과가 캐싱되므로 같은 렌더 사이클에서 여러 번 참조해도 재계산하지 않는다

예시 – 문자열 길이

const message = ref('hello');
const messageLength = computed(() => message.value.length);

3. Vue 템플릿 문법

Vue 템플릿은 HTML 을 확장한 문법으로, 상태 기반 렌더링을 쉽게 해 준다.


3.1 v-text

요소의 textContent 에 값을 채운다.

<p v-text="message"></p>
  • 기존 내용을 완전히 교체한다
  • Mustache 표현식이 복잡해질 때 대체용으로 사용 가능

3.2 v-html (주의)

HTML 문자열을 그대로 렌더링한다.

<div v-html="rawHtml"></div>
  • 사용자 입력을 그대로 넣으면 XSS 취약점이 생긴다
  • 반드시 신뢰할 수 있는 HTML만 렌더링해야 한다

3.3 속성 바인딩: v-bind / :

DOM 속성을 반응형 데이터에 연결한다.

<img :src="imgUrl" />
<div :id="dynamicId"></div>
<input :disabled="isDisabled" />
  • 보통 축약형 : 를 사용
  • JS 값 → HTML 속성으로 매핑

3.4 클래스 바인딩: :class

조건에 따라 클래스를 동적으로 적용할 수 있다.

1) 객체 문법

<div :class="{ active: isActive }"></div>
  • isActive 가 true 이면 active 클래스 추가

2) 객체 자체를 전달

<div :class="classObject"></div>
const classObject = reactive({
  active: true,
  error: false
});

3) 배열 문법

<div :class="['box', dynamicClass]"></div>

3.5 이벤트: v-on / @

<button @click="increase">증가</button>

주요 수식어

수식어의미
.prevent기본 동작 방지
.stop이벤트 전파 중단
.once한 번만 실행
.enterEnter 키일 때만 실행

실무에서 가장 자주 쓰는 부분 중 하나다.


4. 조건 렌더링 & 반복 렌더링

4.1 v-show – CSS 로 토글

<h1 v-show="visible">Hello</h1>
  • DOM 은 항상 존재
  • display: none / block 만 변경
    보이기/숨기기가 매우 자주 바뀌는 경우 유리

4.2 v-if – DOM 자체 제어

<h1 v-if="isOk">OK</h1>
<h1 v-else>No</h1>
  • 조건에 따라 DOM 을 생성/삭제
    렌더링 여부가 자주 변하지 않는 경우 유리

4.3 <template> + v-if

불필요한 wrapper div 를 만들고 싶지 않을 때 사용.

<template v-if="show">
  <h1>A</h1>
  <p>B</p>
</template>
  • 렌더링 결과 안에 <template> 태그는 남지 않는다

4.4 v-for – 반복 렌더링

1) 배열 반복

<li v-for="item in items" :key="item.id">
  {{ item.name }}
</li>

2) 객체 반복

<li v-for="(value, key, index) in obj" :key="key">
  {{ index }} - {{ key }} : {{ value }}
</li>

3) 숫자 범위

<li v-for="n in 10" :key="n">
  {{ n }}
</li>

4.5 :key 의 역할

  • Vue 가 각 반복 요소를 어떻게 구분할지 알려주는 식별자

  • key 가 없으면

    • DOM 재사용 방식이 꼬여서 예상치 못한 동작이 발생할 수 있다
  • key 를 지정하면

    • 변경된 요소만 정확히 업데이트할 수 있다

실무에서는 v-for 를 쓰면 거의 항상 :key 를 같이 쓴다고 보면 된다.


5. v-model – 양방향 바인딩

5.1 기본 패턴

<input v-model="text" />
  • input 값 변경 → text 갱신
  • text 값 변경 → input 값 반영

폼 다룰 때 거의 기본으로 쓰게 되는 문법이다.


5.2 modifiers

.lazy

입력 중에는 반영하지 않고 blur 시점에 반영

<input v-model.lazy="name" />

.number

입력 값을 숫자로 변환 시도 (실패하면 문자열 유지)

<input v-model.number="age" />

.trim

앞뒤 공백 제거 후 바인딩

<input v-model.trim="text" />

5.3 select

<select v-model="selectedFruit">
  <option value="apple">apple</option>
  <option value="banana">banana</option>
</select>
  • selectedFruit 에 선택한 value 가 들어간다

다중 선택

<select v-model="multi" multiple>
  <option value="apple">apple</option>
  <option value="banana">banana</option>
</select>
  • multi 는 배열이 된다

5.4 checkbox

체크된 값들이 배열에 쌓인다.

<input type="checkbox" value="apple" v-model="fruits" />
<input type="checkbox" value="banana" v-model="fruits" />
  • fruits['apple', 'banana'] 같은 형태

5.5 radio

같은 v-model 을 공유하면 단일 선택

<input type="radio" value="male" v-model="gender" />
<input type="radio" value="female" v-model="gender" />
  • gender'male' 또는 'female'

6. watch – 변화 감시

6.1 기본 문법

watch(target, (newVal, oldVal) => {
  // target 값이 바뀔 때마다 실행
});

대표적인 사용처

  • API 호출 트리거
  • localStorage 동기화
  • 특정 조건 충족 시 알림/리다이렉트
  • 폼 검증 로직 실행

6.2 여러 값 감시

watch([x, y], ([nx, ny], [ox, oy]) => {
  // x, y 둘 중 하나라도 바뀌면 실행
});

6.3 함수 기반 감시

watch(
  () => x.value + y.value,
  (newSum, oldSum) => {
    // x 또는 y 가 바뀌어 합이 변하면 실행
  }
);

6.4 watch 옵션

옵션설명
immediate등록 직후 한 번 즉시 실행
once한 번 실행 후 자동 해제
deep객체 내부 중첩 속성까지 감시
flush콜백 실행 타이밍 제어 (post, sync 등)

6.5 watchEffect – 의존성 자동 추적

watchEffect(() => {
  console.log(count.value);
});

특징

  • 콜백 내부에서 사용한 모든 반응형 값들을 자동으로 의존성으로 등록
  • 의존성이 바뀌면 다시 실행
  • 등록 시 즉시 한 번 실행

사용 예

  • 디버깅용 로그
  • 간단한 상태 동기화
  • 종속성을 일일이 나누기 귀찮은 경우

7. nextTick & 라이프사이클

7.1 DOM 업데이트 타이밍과 nextTick

Vue 는 상태가 바뀌면 바로 DOM 을 바꾸지 않고,
한 틱 뒤에 한꺼번에 DOM 업데이트를 수행한다.

그래서 상태 변경 직후에 DOM 을 읽으면 값이 맞지 않을 수 있다.

message.value = 'update';

await nextTick(); // DOM 업데이트 완료 시점까지 대기

console.log('DOM 업데이트 이후에 실행');

사용 상황

  • DOM 변경 후 요소의 높이/위치/스크롤 값 읽기
  • 차트, 외부 라이브러리 렌더링
  • focus() 처럼 실제 DOM 이 있어야 하는 동작

7.2 라이프사이클 훅 흐름

Vue 컴포넌트의 주요 라이프사이클 훅은 다음 순서로 호출된다.

  1. onBeforeMount
  2. onMounted
  3. onBeforeUpdate
  4. onUpdated
  5. onBeforeUnmount
  6. onUnmounted

7.3 각 단계 역할

onBeforeMount

  • 컴포넌트가 DOM 에 붙기 직전
  • 아직 실제 DOM 요소가 없다 (DOM 접근 불가)

onMounted

  • 컴포넌트가 DOM 에 마운트된 직후
  • 실제 DOM 요소 접근 가능
  • 차트, 외부 플러그인 초기화하기 좋은 시점

onBeforeUpdate

  • 반응형 상태 변경으로 DOM 업데이트가 일어나기 직전
  • 기존 DOM 상태를 읽을 수 있다

onUpdated

  • DOM 업데이트 완료 후
  • 변경된 DOM 을 확인하거나 후처리를 할 수 있다

onBeforeUnmount

  • 컴포넌트가 제거되기 직전
  • 타이머, 이벤트 리스너, 구독 등 정리

onUnmounted

  • 컴포넌트가 완전히 제거된 후
  • 정리 이후의 로그 처리나 전역 상태 업데이트 등

마무리

이 글에서 다룬 내용 정리

  • 앱 시작: createAppmount
  • 상태 관리: ref, reactive, computed
  • 템플릿: {{ }}, v-text, v-html, v-bind, :class, @event
  • 조건/반복: v-show, v-if, <template v-if>, v-for + :key
  • 양방향 바인딩: v-model (+ .lazy, .number, .trim)
  • 변화 감시: watch, watchEffect
  • DOM 타이밍: nextTick, 라이프사이클 훅

이 정도만 정확히 이해해도 Vue 3 Composition API 로 웬만한 화면은 충분히 만들 수 있다. 이후에는 라우터, 상태 관리, 컴포넌트 설계 패턴 등을 이어서 확장하면 된다.

profile
개발자 희망자

0개의 댓글