단일 HTML 파일 위에서 JS가 필요한 부분만 교체하며, 실제 페이지 이동 없이 동작하는 웹 애플리케이션
작동 원리
1. 최초 로드 시 애플리케이션에 필요한 주요 리소스 다운로드
2. 페이지 갱신 시 필요한 데이터만 비동기적으로 받아 화면 일부만 동적으로 갱신
3. JavaScript로 클라이언트 측에서 콘텐츠 생성·업데이트
클라이언트에서 콘텐츠를 렌더링하는 방식
작동 원리
1. 사용자가 웹사이트에 요청
2. 서버는 최소한의 HTML + JavaScript 응답
3. 브라우저가 JS를 실행하여 동적으로 페이지 콘텐츠 생성
4. 필요한 데이터는 API를 통해 서버로부터 비동기적으로 가져옴
CSR·SPA 장점
| 항목 | 설명 |
|------|------|
| 빠른 페이지 전환 | 초기 로드 후 필요한 데이터만 가져오므로 전체 페이지 갱신 불필요 |
| 사용자 경험 | 새로고침 없이 네이티브 앱과 유사한 UX 제공 |
| Frontend/Backend 분리 | 역할이 명확해져 대규모 앱 유지보수 용이 |
CSR·SPA 단점
| 항목 | 설명 |
|------|------|
| 느린 초기 로드 | JS 다운로드·파싱·실행까지 페이지가 완전히 렌더링되지 않음 |
| SEO 문제 | 콘텐츠를 나중에 그려서 검색 엔진에 잘 노출되지 않을 수 있음 |
💡 TIP: Next.js, Nuxt.js 같은 하이브리드 프레임워크를 쓰면 SEO와 초기 로드 문제를 대부분 해결할 수 있다.
| 구분 | 설명 |
|---|---|
| SPA | 단일 HTML 파일, JS로 필요한 부분만 교체 |
| MPA | 여러 HTML 파일, 페이지 이동마다 새 파일 로드 |
| CSR | 클라이언트에서 렌더링 |
| SSR | 서버에서 화면을 렌더링 후 완성된 HTML을 클라이언트에 전달 |
사용자 인터페이스를 구축하기 위한 JavaScript 프레임워크
레고 블록처럼 컴포넌트로 화면을 조립하고, 데이터가 바뀌면 화면도 자동으로 바뀌는 반응성이 핵심
| 기능 | 설명 |
|---|---|
| 선언적 렌더링 (Declarative Rendering) | Vue 템플릿 구문으로 JS 상태(데이터)를 기반으로 HTML을 선언적으로 작성 |
| 반응성 (Reactivity) | JS 상태 변경을 추적하고, 변경 발생 시 자동으로 DOM을 업데이트 |
<Root>
├── <Header>
├── <Main>
│ └── <Article> x2
└── <Aside>
└── <Item> x3
Vue 사용 방법: CDN 방식 또는 NPM 설치 방식
<!-- vue_instance.html -->
<div id="app"></div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp } = Vue
const app = createApp({
setup() {}
})
app.mount('#app')
</script>
① CDN 작성 — Vue를 불러오기 위한 script 태그 추가
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
② Application instance — CDN으로 Vue를 사용하는 경우 전역 Vue 객체를 불러오게 됨
const { createApp } = Vue // 구조분해할당으로 createApp 함수를 할당
③ createApp() — 모든 Vue 애플리케이션은 createApp 함수로 새 Application instance를 생성하는 것으로 시작
const app = createApp({
setup() {}
})
④ Root Component — createApp 함수에는 객체(컴포넌트) 가 전달됨
⑤ Mounting the App (앱 연결) — HTML 요소에 Vue Application instance를 탑재(연결)
app.mount('#app') // 각 앱 인스턴스에 대해 mount()는 한 번만 호출 가능
⑥ setup() 함수 — 컴포넌트가 동작하기 전에 미리 준비하는 "시작점", "초기 설정용 함수"
const app = createApp({
setup() {
// 여기서 데이터·함수 정의
}
})
ref()일반 JavaScript 변수를 Vue가 변화를 감지할 수 있는 반응형 객체로 만들어주는 함수
const { createApp, ref } = Vue
const app = createApp({
setup() {
const message = ref('Hello vue!')
console.log(message) // ref 객체
console.log(message.value) // Hello vue!
return { message }
}
})
ref(0)을 선언하면 → { value: 0 } 형태의 객체가 됨 (Python의 dictionary와 유사).value 생략 가능 (자동으로 unwrap됨)<!-- vue_instance.html -->
<div id="app">
<h1>{{ message }}</h1> <!-- .value 안 써도 됨 -->
</div>
| 구분 | 값 변경 시 화면 |
|---|---|
ref() 반응형 변수 | 자동으로 업데이트 ✅ |
일반 let 변수 | 화면 갱신 안 됨 ❌ |
ref 객체가 필요한 이유: JavaScript에서는 일반 변수의 접근·변형을 감지할 방법이 없기 때문에, 참조 자료형의 객체 타입으로 구현하여 Vue가 변화를 추적할 수 있게 함
const app = createApp({
setup() {
const message = ref('Hello vue!')
return {
message // 반드시 객체를 반환해야 템플릿에서 사용 가능
}
}
})
createApp()에 전달되는 객체 = Vue 컴포넌트setup() 함수 내에서 선언 후 반드시 객체로 반환v-on 디렉티브로 DOM 이벤트를 수신하고, 함수 내에서 반응형 변수를 변경하여 UI 업데이트
<div id="app">
<button v-on:click="increment">버튼</button>
<p>{{ number }}</p>
</div>
const app = createApp({
setup() {
const number = ref(0)
const increment = function () {
number.value++
}
return { number, increment }
}
})
템플릿 unwrap은 ref가 setup에서 반환된 객체의 최상위 속성일 경우에만 자동 적용됨
// ❌ 문제 상황
const object = { id: ref(0) }
// {{ object.id + 1 }} → [object object]1 (unwrap 안 됨)
// ✅ 해결: id를 객체에서 분해하여 최상위 속성으로 만들기
const { id } = object
// {{ id + 1 }} → 1
// ✅ 단, {{ }} 최종 평가값인 경우는 unwrap 가능
// {{ object.id }} === {{ object.id.value }} → 0
Vue = 컴포넌트 기반 + 반응형 데이터 바인딩
ref() = 일반 변수 → 반응형 객체로 변환
템플릿 = JS 상태를 선언적으로 HTML에 표현
v-on = 이벤트 리스너 디렉티브