반응형
3장: 반응성과 생명주기 - 살아 움직이는 컴포넌트
반응성(Reactivity)은 Vue의 가장 핵심적인 특징입니다. 데이터가 변경되면 화면이 자동으로 업데이트되는 원리를 이해하고, 컴포넌트의 '생명'과도 같은 생명주기 훅을 다루는 방법을 배웁니다.
1. 핵심 개념
반응형 상태(Reactive State): Vue는 JavaScript 객체를 프록시(Proxy)하여, 객체의 속성이 변경되는 것을 감지하고 관련 UI를 자동으로 업데이트합니다.
ref: 원시 값(primitive value, 예:String,Number,Boolean)을 반응형으로 만들기 위해 사용합니다.ref는.value속성을 가진 객체를 반환하며, 스크립트 내에서는 항상.value로 값에 접근해야 합니다. (템플릿에서는 자동으로.value가 풀려서 바로 사용 가능)import { ref } from 'vue'const count = ref(0);console.log(count.value); // 0count.value++;
reactive: 객체(Object)나 배열(Array)을 반응형으로 만듭니다.ref와 달리, 객체의 속성에 직접 접근하고 변경할 수 있습니다.import { reactive } from 'vue'const state = reactive({ count: 0 });state.count++;
생명주기 훅(Lifecycle Hooks): 컴포넌트가 생성되고(mount), 업데이트되고(update), 사라지는(unmount) 등 특정 시점에 실행할 코드를 등록할 수 있는 함수들입니다. Composition API에서는
onMounted,onUpdated,onUnmounted등의 함수를 사용합니다.
2. 예제 코드
예제 1: ref로 카운터 만들기
버튼을 클릭하면 숫자가 증가하는 간단한 카운터 예제입니다.
<!-- src/components/SimpleCounter.vue -->
<script setup>
import { ref } from 'vue';
// 'count'라는 이름의 반응형 상태를 만들고, 초기값은 0으로 설정
const count = ref(0);
// 버튼 클릭 시 count 값을 1 증가시키는 함수
function increment() {
count.value++;
}
</script>
<template>
<div>
<p>현재 카운트: {{ count }}</p>
<button @click="increment">증가</button>
</div>
</template>
예제 2: onMounted로 데이터 가져오기
컴포넌트가 처음 렌더링될 때 외부 API에서 데이터를 가져와 반응형 상태에 저장하는 예제입니다.
<!-- src/components/PostViewer.vue -->
<script setup>
import { ref, onMounted } from 'vue';
const post = ref(null);
const loading = ref(true);
// onMounted 훅은 컴포넌트가 DOM에 마운트된 후 한 번만 실행됩니다.
onMounted(async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
const data = await response.json();
post.value = data; // 가져온 데이터로 post 상태 업데이트
} catch (error) {
console.error('데이터를 가져오는 데 실패했습니다:', error);
} finally {
loading.value = false; // 로딩 상태 종료
}
});
</script>
<template>
<div>
<h1>게시글 뷰어</h1>
<p v-if="loading">로딩 중...</p>
<div v-else>
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
</div>
</template>
3. 연습 문제
문제 1: 색상 변경기 만들기
- 요구사항:
ref를 사용하여 현재 색상 이름을 저장하는ColorPicker.vue컴포넌트를 만드세요. - 세부사항:
- "Red", "Green", "Blue" 세 개의 버튼을 만듭니다.
- 현재 선택된 색상을 표시하는
div를 만듭니다. (예:<div :style="{ color: currentColor }">현재 색상: {{ currentColor }}</div>) - 각 버튼을 클릭하면 해당 색상 이름으로
ref상태가 변경되고,div의 글자 색도 함께 바뀌어야 합니다.
- 도전과제:
div의 글자 색뿐만 아니라 배경색도 함께 변경해보세요.
문제 1 정답 예시
<script setup>
import { ref } from 'vue';
const color = ref('black');
</script>
<template>
<div>
<div :style="{
color: color,
backgroundColor: '#f0f0f0',
padding: '10px',
fontSize: '20px'
}">
현재 선택된 색상: {{ color }}
</div>
<button @click="color = 'red'">Red</button>
<button @click="color = 'green'">Green</button>
<button @click="color = 'blue'">Blue</button>
</div>
</template>
문제 2: 마우스 좌표 추적기 만들기
- 요구사항:
onMounted와onUnmounted를 사용하여 마우스의 현재 X, Y 좌표를 화면에 표시하는MouseTracker.vue컴포넌트를 만드세요. - 세부사항:
reactive를 사용하여 마우스 좌표를 저장할position상태를 만듭니다. (초기값:{ x: 0, y: 0 })onMounted훅을 사용하여 컴포넌트가 마운트될 때window객체에mousemove이벤트 리스너를 추가합니다.- 이벤트 리스너 콜백 함수에서는
position상태를 업데이트합니다. - (중요)
onUnmounted훅에서 컴포넌트가 언마운트될 때removeEventListener를 사용하여 이벤트 리스너를 제거해야 합니다. (메모리 누수 방지)
- 도전과제: 마우스가 움직일 때만 좌표가 업데이트되도록 최적화해보세요. (이미 기본적으로 그렇게 동작합니다. 왜 그런지 생각해보세요.)
문제 2 정답 예시
<script setup>
import { reactive, onMounted, onUnmounted } from 'vue';
const position = reactive({ x: 0, y: 0 });
const handleMouseMove = (event) => {
position.x = event.clientX;
position.y = event.clientY;
};
// 컴포넌트가 마운트될 때 이벤트 리스너 추가
onMounted(() => {
window.addEventListener('mousemove', handleMouseMove);
console.log('이벤트 리스너가 추가되었습니다.');
});
// 컴포넌트가 언마운트될 때 이벤트 리스너 제거
onUnmounted(() => {
window.removeEventListener('mousemove', handleMouseMove);
console.log('이벤트 리스너가 제거되었습니다.');
});
</script>
<template>
<p>
마우스 좌표: X: {{ position.x }}, Y: {{ position.y }}
</p>
</template>
반응형
'프론트엔드 > 뷰' 카테고리의 다른 글
| [Vue] 9장: 스타일링 - 컴포넌트에 옷 입히기 (0) | 2025.09.23 |
|---|---|
| [Vue] 8장: 컴포저블과 반응성 심화 - Vue 능력 끌어올리기 (0) | 2025.09.23 |
| [Vue] 7장: 폼과 `v-model` - 사용자의 입력 받기 (0) | 2025.09.23 |
| [Vue] 6장: 리스트 렌더링 - 동적인 목록 만들기 (0) | 2025.09.23 |
| [Vue] 5장: 조건부 렌더링 - 상황에 맞는 UI 보여주기 (0) | 2025.09.23 |
| [Vue] 4장: 이벤트 핸들링 - 사용자와의 상호작용 (0) | 2025.09.23 |
| [Vue] 2장: Props - 컴포넌트에 생명 불어넣기 (2) | 2025.09.23 |
| [Vue] 1장: 템플릿과 컴포넌트 - Vue.js의 첫인상 (0) | 2025.09.23 |