리스트 렌더링
v-for
배열을 리스트로 렌더링 > item in tiems 형식의 특별한 문법이 필요
items 배열 item 반복되는 엘리먼트의 별칭
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
//tem
<li v-for="item in items">
{{ item.message }}
</li>
//인덱스도 지원
const parentMessage = ref('Parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
//tem
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
v-for 의 변수 범위 (js 와 비슷함) 분해 할당 가능
const parentMessage = 'Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// forEach의 콜백 함수 외부에 있는 `parentMessage`에 대한 접근 가능.
// 반면 `item`과 `index`는 콜백함수 내부에서만 접근 가능.
console.log(parentMessage, item.message, index)
})
분해할당
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- index 별칭도 사용 -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
중첩된 v-for의 경우, 중첩된 함수와 유사한 범위를 가짐, 상위 범위에 대한 접근 권한을 가짐
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
in 대신 of 를 사용해서 js 반복문 문법처럼 사용 가능
<div v-for="item of items"></div>
객체에 v-for 사용하기
const myObject = reactive({
title: 'Vue에서 목록을 작성하는 방법',
author: '홍길동',
publishedAt: '2016-04-10'
})
<ul>
<li v-for="value in myObject" v-bind:key="value">
{{ value }}
</li>
</ul>
<li v-for="(value, key) in myObject" v-bind:key="key">
{{ key }}: {{ value }}
</li>
<li v-for="(value, key, index) in myObject" v-bind:key="key">
{{ index }}. {{ key }}: {{ value }}
</li>
숫자 범위에 v-for 사용하기
1 ...n 범위를 기준으로 템플릿을 여러 번 반복 * n은 1부터 시작한다
<span v-for="n in 10" v-bind:key="n">{{ n }}</span>
//12345678910
<template>에서 v-for 사용하기
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
v-if에 v-for 사용하기 (권장되지 않음)
같은 노드에 존재할 때 v-if 가 v-for 보다 우선순위가 높기 때문에 v-if 조건문에서 v-for 변수에 접근 불가
<!--
"todo" 속성이 인스턴스에 정의되어 있지 않기 때문에 에러가 발생
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
<template> 로 감싼후 해결 가능
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
key를 통한 상태유지
Vue 가 v-for 로 렌더링된 리스트를 업데이트할 때, 기본적으로 in-place patch 전략을 사용
리스트 아이템의 순서가 변경된 경우, 아이템의 순서와 일치하도록 DOM 엘리먼트를 이동하는 대신
변경이 필요한 인덱스의 엘리먼트들을 제자리에서 패치해 아이템을 렌더링
효율적이지만, 리스트 렌더링 출력이 자식 컴포넌트 상태 또는 임시 DOM 상태(ex: 양식 입력 값)에 의존하지 않는경우에만 유효
<div v-for="item in items" :key="item.id">
<!-- 내용 -->
</div>
// tem 안에서 쓸거면 key 는 tem 에 있어야한다
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
*** 여기서 key 는 v-bind 와 결합되는 특수 속성, 객체 v-for 의 두번째 별칭인 key와 다름 (ex:title, name...)
반복되는 DOM 컨텐츠가 단순하거나 (컴포넌트x, 상태를 가지는 DOM 엘리먼트x), 의도적으로 기본 리스트 렌더링 동작을 통해 성능 향상을 필요로 하지 않는다면 가능한 언제나 v-for 는 key 속성과 함께 사용하는 것을 권장
컴포넌트에 v-for 사용하기
컴포넌트에 v-for 를 직접 사용 key 넣기
<MyComponent v-for="item in items" :key="item.id" />
*컴포넌트는 자체적으로 구분된 범위가 있기 때문에 컴포넌트에 데이터를 자동으로 전달하지 않음
이유 -> 그렇게 하지 않으면 v-for를 사용해야만 컴포넌트 사용이 가능하도록 의존관계가 되기 때문
이유2 -> 데이터 명시 전달 방법은 v-for 를 사용하지 않는 다른 상황에서도 컴포넌트가 기능을 할수 있게 하기 위
반복된 데이터를 컴포넌트에 전달하려면 props 를 사용
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
배열 변경 감지
수정 메서드
Vue 는 반응형 배열의 변경 메소드가 호출 되는것을 감지하여, 필요한 업데이트를 발생시킴
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
배열 교체
filter(), concat() 및 slice() 는 원본 배열을 수정하지 않고 항상 새 배열을 반환
이전 배열을 새 배열로 교체해야함
// `items`는 값이 있는 배열의 ref라고 가정된 경우입니다.
items.value = items.value.filter((item) => item.message.match(/Foo/))
이렇게 해도 Vue는 기존 DOM을 버리지 않고 재사용을 최대화 하기 위해 몇 가지 스마트 휴리스틱을 구현,
이전 배열을 다른 배열로 바꾸는 과정에서 서로 중복되는 객체를 가지는 부분을 효율적으로 처리함
필터링/정렬 결과 표시
계산된 속성을 만들어서 원본 데이터를 실제로 수정하거나 교체하지 않고 필터링하거나 정렬된 결과를 표시
const numbers = ref([1, 2, 3, 4, 5])
const evenNumbers = computed(() => {
return numbers.value.filter((n) => n % 2 === 0)
})
//tem
<li v-for="n in evenNumbers">{{ n }}</li>
계산된 속성이 실현 가능하지 않은 상황 (ex. v-for 루프 내부)
const sets = ref([
[1, 2, 3, 4, 5],
[6, 7, 8, 9, 10]
])
function even(numbers) {
return numbers.filter((number) => number % 2 === 0)
}
<ul v-for="numbers in sets">
<li v-for="n in even(numbers)">{{ n }}</li>
</ul>
계산된 속성에서 resvers() 와 sort()사용에 주의, 이 두가지 방법은 원본 배열을 수정하므로 계산된 속성의 getter 함수에서
피해야함 -> 메소드 호출 전 원본 배열의 복사본을 만들어야함
- return numbers.reverse()
+ return [...numbers].reverse()