반응형
6장: 리스트 렌더링 - 동적인 목록 만들기
배열 데이터를 UI에 동적으로 렌더링하는 방법을 배웁니다. Vue가 리스트의 변경 사항을 효율적으로 추적하고 업데이트하는 데 필요한 key 속성의 중요성을 이해합니다.
1. 핵심 개념
v-for디렉티브: 배열이나 객체를 기반으로 엘리먼트 또는 템플릿 블록을 여러 번 렌더링하는 데 사용됩니다.- 문법:
item in items형식.items는 원본 데이터 배열이고item은 배열에서 반복되고 있는 현재 요소의 별칭입니다. v-for는(item, index) in items형태로 두 번째 인자인index도 받을 수 있습니다.
- 문법:
key:v-for를 사용할 때 반드시 제공해야 하는 특별한 속성입니다.- 왜 필요한가?: Vue는
key를 사용하여 각 노드의 ID를 추적하고, 리스트가 변경될 때 기존 엘리먼트를 재사용하고 재정렬할지 여부를 결정합니다.key가 없으면 Vue는 리스트를 효율적으로 업데이트하기 어렵습니다. - 좋은 Key의 조건:
- 고유성: 형제 노드 사이에서 유일해야 합니다.
- 안정성: 리렌더링 되더라도 변하지 않아야 합니다. 항목의 순서가 바뀌어도 해당 항목의
key는 그대로 유지되어야 합니다.
- 무엇을 Key로 사용해야 하는가?: 데이터에 포함된 고유 ID(예: 데이터베이스의
id,uuid)를 사용하는 것이 가장 좋습니다. - 최후의 수단,
index: 마땅한key가 없을 때index를key로 사용할 수 있지만, 권장하지 않습니다. 리스트의 순서가 바뀌거나 항목이 추가/삭제될 때key가 불안정해져 성능 저하와 예기치 않은 버그(특히 폼 입력과 관련된)를 유발할 수 있습니다.
- 왜 필요한가?: Vue는
2. 예제 코드
예제 1: 간단한 숫자 리스트 렌더링
v-for를 사용하여 숫자 배열을 <li> 엘리먼트 배열로 변환합니다.
<script setup>
import { ref } from 'vue';
const numbers = ref([1, 2, 3, 4, 5]);
</script>
<template>
<ul>
<!--
v-for로 numbers 배열을 순회합니다.
각 li 엘리먼트에 고유한 key를 부여합니다.
이 경우 number 자체가 고유하므로 key로 사용할 수 있습니다.
-->
<li v-for="number in numbers" :key="number">
{{ number }}
</li>
</ul>
</template>
예제 2: 객체 배열과 컴포넌트 렌더링
데이터가 객체 배열일 경우, 각 객체를 컴포넌트에 prop으로 전달하여 렌더링하는 것이 일반적입니다.
<!-- src/components/TodoItem.vue -->
<script setup>
defineProps({
todo: Object
});
</script>
<template>
<li :class="{ completed: todo.completed }">
{{ todo.text }}
</li>
</template>
<style scoped>
.completed {
text-decoration: line-through;
color: #aaa;
}
</style>
<!-- src/components/TodoList.vue -->
<script setup>
import { reactive } from 'vue';
import TodoItem from './TodoItem.vue';
const todos = reactive([
{ id: 'a1', text: 'Vue 공부하기', completed: true },
{ id: 'b2', text: '운동하기', completed: false },
{ id: 'c3', text: '저녁 장보기', completed: false },
]);
</script>
<template>
<div>
<h1>오늘의 할 일</h1>
<ul>
<!--
v-for로 컴포넌트를 렌더링합니다.
데이터의 고유 ID인 todo.id를 key로 사용합니다.
todo 객체 전체를 props로 전달합니다.
-->
<TodoItem
v-for="item in todos"
:key="item.id"
:todo="item"
/>
</ul>
</div>
</template>
3. 연습 문제
문제 1: FruitList 컴포넌트 만들기
- 요구사항: 과일 이름 배열을 받아
<ul>리스트로 렌더링하는FruitList.vue컴포넌트를 만드세요. - 세부사항:
const fruits = ['사과', '바나나', '오렌지', '딸기', '포도'];배열을 사용합니다.v-for디렉티브를 사용하여 각 과일 이름을<li>태그로 렌더링합니다.- (중요)
:key속성을 적절히 설정하세요. 이 경우, 과일 이름이 중복되지 않는다고 가정하고 이름 자체를key로 사용할 수 있습니다.
- 도전과제:
index를key로 사용했을 때와 과일 이름을key로 사용했을 때 어떤 차이가 있을지 생각해보세요. (만약 리스트의 순서가 바뀐다면?)
문제 1 정답 예시
<script setup>
import { ref } from 'vue';
const fruits = ref(['사과', '바나나', '오렌지', '딸기', '포도']);
</script>
<template>
<div>
<h2>과일 목록</h2>
<ul>
<!-- 이 예제에서는 fruit 이름이 고유하므로 key로 사용 가능합니다. -->
<!-- index를 key로 사용하는 것은 피하는 것이 좋습니다: <li v-for="(fruit, index) in fruits" :key="index">{{ fruit }}</li> -->
<li v-for="fruit in fruits" :key="fruit">
{{ fruit }}
</li>
</ul>
</div>
</template>
문제 2: UserList 컴포넌트 만들기
- 요구사항: 사용자 정보가 담긴 객체 배열을 받아, 각 사용자의 이름과 이메일을 리스트로 보여주는
UserList.vue컴포넌트를 만드세요. - 세부사항:
- 아래의
users배열을 사용합니다.const users = [ { id: 101, name: '최동진', email: 'kafella@example.com' }, { id: 102, name: 'Gemini', email: 'gemini@example.com' }, { id: 103, name: 'Vue', email: 'vue@example.com' }, ]; v-for를 사용하여 각user객체를<li>엘리먼트로 변환합니다.- 각
<li>안에는 "이름: [name], 이메일: [email]" 형식의 텍스트가 포함되어야 합니다. - 각
<li>의:key로는user.id를 사용하세요.
- 아래의
- 도전과제: 각 리스트 항목을 별도의
User.vue컴포넌트로 분리하고,UserList.vue에서는User컴포넌트를v-for로 렌더링하도록 구조를 변경해보세요.
문제 2 정답 예시
<!-- src/components/User.vue -->
<script setup>
defineProps({
user: Object
});
</script>
<template>
<li>
이름: {{ user.name }}, 이메일: {{ user.email }}
</li>
</template>
<!-- src/components/UserList.vue -->
<script setup>
import { reactive } from 'vue';
import User from './User.vue';
const users = reactive([
{ id: 101, name: '최동진', email: 'kafella@example.com' },
{ id: 102, name: 'Gemini', email: 'gemini@example.com' },
{ id: 103, name: 'Vue', email: 'vue@example.com' },
]);
</script>
<template>
<div>
<h2>사용자 목록</h2>
<ul>
<User v-for="user in users" :key="user.id" :user="user" />
</ul>
</div>
</template>
반응형
'프론트엔드 > 뷰' 카테고리의 다른 글
| [Vue] 10장: Vue Router - 페이지 이동과 목차 만들기 (0) | 2025.09.23 |
|---|---|
| [Vue] 9장: 스타일링 - 컴포넌트에 옷 입히기 (0) | 2025.09.23 |
| [Vue] 8장: 컴포저블과 반응성 심화 - Vue 능력 끌어올리기 (0) | 2025.09.23 |
| [Vue] 7장: 폼과 `v-model` - 사용자의 입력 받기 (0) | 2025.09.23 |
| [Vue] 5장: 조건부 렌더링 - 상황에 맞는 UI 보여주기 (0) | 2025.09.23 |
| [Vue] 4장: 이벤트 핸들링 - 사용자와의 상호작용 (0) | 2025.09.23 |
| [Vue] 3장: 반응성과 생명주기 - 살아 움직이는 컴포넌트 (0) | 2025.09.23 |
| [Vue] 2장: Props - 컴포넌트에 생명 불어넣기 (2) | 2025.09.23 |