01. Vue.js 입문: 핵심 구조와 렌더링
Vue의 선언적 렌더링, 반응성, 컴포넌트 구조와 SPA 동작 방식을 한 번에 정리.
Vue.js란?
Vue.js는 사용자 인터페이스를 만들기 위한 JavaScript 프레임워크다. 핵심은 상태를 직접 DOM에 맞춰 관리하는 대신, 상태와 화면의 관계를 선언하는 것이다.
사용자 행동
↓
상태 변경
↓
Vue의 반응성 시스템
↓
필요한 화면 갱신
순수 JavaScript에서는 변경할 요소를 찾고 값을 직접 바꾼다.
const countElement = document.querySelector('#count')
let count = 0
count += 1
countElement.textContent = count
만약 프로젝트에서 관리할 요소가 많아진다면, 일일히 다 관리하는 것은 분명히 무리일것이다.
다행히도 Vue는 이러한 변경 요소를 자동으로 처리해준다.
개발자는 DOM 변경 순서보다 데이터 흐름과 사용자 동작에 집중할 수 있다.
Vue에서는 상태를 바꾸면 템플릿이 그 상태를 따라 갱신된다.
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">{{ count }}</button>
</template>
Vue의 네 가지 핵심
1. 선언적 렌더링
템플릿에는 상태가 화면에 어떻게 보일지 작성한다. 상태가 바뀌면 Vue가 화면을 다시 계산한다.
| 명령형 DOM 조작 | Vue의 선언적 렌더링 |
|---|---|
| 변경할 요소를 직접 찾는다. | 상태와 템플릿의 관계를 작성한다. |
| DOM 수정 시점을 직접 관리한다. | Vue가 상태 변경을 추적한다. |
| 화면이 커질수록 변경 코드가 흩어지기 쉽다. | 화면 로직을 컴포넌트 안에 모을 수 있다. |
2. 반응성
ref()와 reactive()로 만든 상태는 변경을 추적할 수 있다. Vue는 렌더링에 사용된 상태가 바뀌면 관련 부분을 자동으로 갱신한다.
import { reactive, ref } from 'vue'
const count = ref(0)
const user = reactive({
name: 'Lee',
loggedIn: false
})
ref: 하나의 값이나 교체할 객체를 다룰 때 기본적으로 사용한다. (실무에서는 일단 ref를 고정으로 두고 쓴다한다.)reactive: 관련된 여러 값을 객체로 묶어 다룰 때 사용할 수 있다.
3. 컴포넌트
Vue는 화면을 독립적이고 재사용 가능한 컴포넌트로 나눈다.
App
├── AppHeader
├── ProductList
│ └── ProductCard
└── AppFooter
각 컴포넌트는 보통 하나의 .vue 파일에 템플릿, 로직, 스타일을 함께 담는다. 이를 SFC(Single-File Component)라고 한다.
<script setup>
const message = 'Vue 시작!'
</script>
<template>
<h1>{{ message }}</h1>
</template>
<style scoped>
h1 {
color: #42b883;
}
</style>
컴포넌트 사이에서는 보통 부모가 props로 데이터를 내려주고, 자식이 emit으로 이벤트를 알린다.
4. 렌더링과 Virtual DOM
HTML은 문서이고, DOM(Document Object Model)은 브라우저가 HTML을 메모리에 객체 트리로 표현한 결과다.
JavaScript와 Vue는 이 DOM을 통해 화면을 변경한다.
Vue의 기본 렌더링 흐름은 다음과 같다.
템플릿 + 상태
↓
Virtual DOM 생성
↓
이전 결과와 새 결과 비교
↓
필요한 실제 DOM 반영
Vue가 관리하는 DOM을 querySelector()로 자주 직접 수정하면 상태와 화면이 서로 달라질 수 있다.
DOM 접근이 꼭 필요하면 템플릿 ref와 onMounted()를 사용한다.
<script setup>
import { onMounted, ref } from 'vue'
const inputElement = ref(null)
onMounted(() => {
inputElement.value?.focus()
})
</script>
<template>
<input ref="inputElement" />
</template>
Vue와 SPA
SPA(Single Page Application)는 최초에 애플리케이션을 불러온 뒤, 이동할 때 페이지 전체를 다시 받기보다 필요한 화면과 데이터를 바꾸는 방식이다.
브라우저
├── Vue Router: URL과 화면 연결
├── Pinia: 여러 화면이 공유하는 상태
└── fetch/Axios: API 통신
장점
- 페이지 전환이 자연스럽고 애플리케이션 같은 사용자 경험을 만들기 좋다.
- 사용자에게 압도적인 UX 경험 전달해줌
- 프론트엔드 화면과 백엔드 API의 역할을 분리하기 쉽다.
- MVVM 모델을 생각해보자!
- 이미 받은 CSS와 JavaScript를 재사용하며 필요한 데이터만 요청할 수 있다.
- 데이터 전송량을 아낄 수 있는 장점이 있다.
참고자료
고려할 점
다만 아시다시피 모든 기술 Trade-off 가 존재합니다.. 장점만 있는 것은 아니다.
- 첫 화면에 필요한 JavaScript가 크면 초기 로딩이 느려질 수 있다.
- 새로고침해도 같은 URL이 열리도록 서버의 fallback 설정이 필요하다.
- CSR만 사용하면 검색 엔진과 링크 미리보기를 위한 별도 전략이 필요할 수 있다.
- 상태가 많아지면 지역 상태와 전역 상태의 경계를 정해야 한다.
다행히도 이런 문제를 해결할 방법들이 존재한다.
- 코드 분할(Code Splitting):
- 애플리케이션 코드를 여러 파일로 나누고, 필요한 시점에 필요한 코드만 불러오는 방식. 초기 로딩 속도를 줄이는 데 사용
- SSR(Server-Side Rendering):
- 서버에서 HTML을 먼저 완성해 브라우저에 전달하는 방식. 초기 화면 표시가 빠르고 SEO에 유리.
- SSG(Static Site Generation):
- 빌드 시점에 HTML 파일을 미리 생성해 두고 사용자에게 제공하는 방식. 속도가 빠르고 서버 부담이 적다.
아무튼!
모든 Vue 프로젝트가 SPA일 필요는 없으므로 서비스의 요구 사항에 맞춰 선택한다.
학습 순서
추천 순서는 아래와 같다
- JavaScript의 객체, 배열, 함수, 모듈, 비동기 문법 (이거는 꼭 해야하는 걸까..)
- 템플릿 문법과 디렉티브 (이거는 무적권 해야한다.)
ref,computed, 이벤트 처리- 컴포넌트와
props,emit,slot(꽤나 중요하다.) - Vue Router와 API 통신
- 여러 화면이 공유하는 상태가 생길 때 Pinia
정리
요약
상태를 바꾸면 Vue가 그 상태를 사용하는 화면을 갱신한다.
그 위에 컴포넌트, 라우팅, 상태 관리, API 통신을 필요한 만큼 조합하면 된다.
마치 뷔페 와서 먹고 싶은거 담는다고 생각하고 공부하자
참고 자료
- Vue 공식 문서: Introduction
- Vue 공식 문서: Rendering Mechanism
- Vue 공식 문서: State Management
- .NET MAUI MVVM 아키텍처 공식 문서
COMMENTS
GitHub 계정으로 로그인하여 댓글을 남길 수 있습니다. 댓글은 GitHub Discussions에 공개 저장되며, 작성 내용과 GitHub 프로필 정보가 다른 방문자에게 보일 수 있습니다.