v-for
배열에 기반을 둔 아이템의 리스트를 렌더링하기위해 v-for 지시어를 사용할 수 있다. v-for 지시어는 item in items의 형태인 특별한 구문을 필요로 하는데, items는 소스 데이터 배열이고, item은 반복되는 배열의 원소의 별칭이다.
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
<li v-for="item in items">
{{ item.message }}
</li>
v-for 범위 안에서, 템플릿 표현식은 모든 부모 범위 프로퍼티에 접근할 수 있다. 게다가, v-for은 현재 아이템의 인겟스를 두번째 옵션 별칭으로 지원한다 :
const parentMessage = ref('parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
Parent - 0 - Foo Parent - 1 - Bar |
v-for의 변수 범위는 다읨의 자바스크립트와 비슷하다:
const parentMessage ='Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// 외부 범위인 'parentMessage'에 접근 권한이 있다.
// 하지만 'item'과 'index'는 여기서만 유효하다.
console.log(parentMessage, item.message, index)
})
어떻게 v-for 값이 forEach 콜백의 함수 시그니쳐와 어떻게 일치하는지 확인하라. 실제로, 구조분할 함수 아규먼트와 비슷하게 v-for 아이템 별칭을 구조분할로 사용할 수 있다.
<li v-for="{ meesage } in items">
{{ message }}
</li>
<!-- index 별칭과 함께 -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
중첩된 v-for로, 범위는 또한 중첩 함수와 비슷하게 동작한다. 각각의 v-for 범위는 부모 범위에 접근한다.
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
in을 대신하는 구획문자로 of를 사용할 수 있다. iterator를 위한 자바스크립트의 구문에 좀더 가깝다:
<dic v-for="item of items"></div>
객체와 v-for
객체의 프로퍼티를 반복하기위해 v-for를 사용할 수 있습니다.
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
<ul>
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
프로퍼티의 이름을 위한 두번째 별칭을 제공할 수도 있습니다(키로 알려진):
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
index를 위한 별칭도 제공할 수 있습니다:
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
주의 객체를 반복할 때, 순서는 object.keys()의 정렬순서를 따른다, 자바스크립트 엔진의 실행에 따라 일관성을 보장하지 않는다. |
범위와 v-for
v-for에 숫자를 줄 수도 있다. 이 경우에, 1...n같은 범위에 기초해서, 여러번 템플릿을 반복할것이다,
<span v-for="n in 10">{{ n }}</span>
여기서 n은 0대신에 1을 초기값으로 시작한다.
템플릿에 v-for
템플릿 v-if 와 비슷하게, 여러 원소의 블록을 렌더링하기 위해 v-for를 <template>태그와 사용할 수 있다. 예를 들면 :
<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보다 높은 우선순위를 가진다. v-if 조건은 v-for의 변수로 접근할 수 없다는 것을 의미한다.
<--
프로퍼티'todo'가 인스턴스에 정의되지 않았기 때문에,
에러를 발생 시킨다.
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
래핑된 <template> 태그로 v-for를 옮겨서 고칠 수 있다.(더 명백하다)
<tmeplate v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
key로 상태를 유지
뷰가 v-for로 렌더링된 원소들의 목록을 업데이트 할 때, 기본적으로 "in-place patch"전략을 사용한다. 만약 데이터 아이템의 순서가 변경 되었을 때, 아이템들의 순서를 매칭하기위해 돔 엘리먼트를 옮기는 대신에, 뷰는 각각의 엘리먼트를 제자리에서 패치하고, 특정 인덱스에서 렌더링되야 하는 내용을 반영합니다.
이 기본전략을 효율적이지만, 일시적인 돔 상태 (form input values같은) 또는 자식 컴포넌트 상태에 의존하지 않고 목록이 렌더링될때에만 적합합니다.
각각의 노드의 신원을 추적할 수 있도록 뷰에게 힌트를 줘서, 존재하는 엘리먼트들을 재사용하고 정렬할 수 있도록, 각각의 아이템의 특별한 key 어트리뷰트를 제공해야 한다:
<div v-for="item in items" :key="item.id">
<!-- content -->
</div>
<template v-for>를 사용할 때, 키는 <template> 컨테이너에 배치되어야 한다.
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
주의 키는 v-bind와 바운드 되는 특별한 애트리뷰트 이다. 객체에 v-for를 사용할 떄 프로퍼티 key 변수와 혼동하지 말아야 한다. |
반복하는 DOM 컨텐츠가 단순하거나(즉, 상태저장 DOM 엘리먼트나 컴포넌트를 포함하지 않는) 의도적으로 성능을 높이기 위해 기본 동작에 의존하는 경우가 아니라면, 가능한 언제든지 v-for과함께 key 어트리뷰트를 제공하는걸 추천한다.
key바인딩은 원시값을 넣어야 한다 - 즉, string이나 number를 넣어야 한다. v-for 키값으로 객체를 쓰지 마라. key 어트리뷰트의 상세 사용법은 key API 문서를 참고해달라.
컴포넌트와 v-for
// 이 섹션은 컴포넌트에 대한 지식이 있다고 가정한다. 가볍게 스킵하고 다음에 봐도 된다.
일반적인 객체와 같이 컴포넌트에 v-for를 직접 사용할 수 있다.(key를 제공하는걸 잊지마라)
<my-component v-for="item in items" :key="item.id"></my-component>
컴포넌트로 어떤 데이터를 자동적으로 넘기지 않는데, 컴포넌트가 그들 스스로 격리된 범위를 가지고 있기 때문이다. 컴포넌트에 반복되는 데이터를 넘기기 위해, 우리는 props를 사용할 수 있다.
<my-component
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
></my-component>
컴포넌트에 자동적으로 item을 삽입하지 않는 이유는, v-for이 어떻게 동작하는 지에 컴포넌트가 밀접한 결합력을 갖도록 하게 만들기 때문이다. 데이터가 어디서 오는지 명시하는 것은 다른 상황에 컴포넌트를 재사용가능하도록 만든다.
각각 인스턴스에 다른 데이터는 넘기는, v-for를 사용한 컴포넌트의 목록이 어떻게 렌더링 되는지 보고싶다면 simple todo list 예제를 살펴보라.
배열 변경 탐지
상태변화 메소드
뷰는 관찰되는 배열의 상태변화 메소드를 래핑해서, 뷰 업데이트를 쫒을 수 있다. 래핑 메소드는 다음과 같다:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
배열 교체
상태변화 메소드는 이름에서 알수 있듯, 그들이 호출된 오리지널 객체를 상태변화 시킨다. 대조적으로, filter(), concat(), slice()와 같은 항상 새로운 배열을 리턴하고 오리지널 객체를 상태변화 시키지않는 non-mutating 메소드도 있다. non-mutating 메소드를 사용할 때, 새로운 배열로 사용하던 배열을 교체해줘야 한다.
// 'item' 은 배열값의 ref다
items.value = items.value.filter((item) => item.message.amtch(/Foo/))
아마 당신은 이것이 존재하는 DOM을 버리고 전체 리스트를 재렌더링 한다고 생각할지도 모른다 - 다행히, 그렇지 않다. 뷰는 최대한 돔 엘리먼트를 재사용하는 똑똑한 방법(heuristics)을 구현해서, 중복된 객체를 담고있는 다른 배열로 교체해도 매우 효율적인 수행이 된다.
필터링/ 정렬된 결과 표시
때로 오리지널 데이터의 실제 상태변화나 리세팅 없이 배열의 필터링된, 정렬된 버전을 보고싶은 경우가 있습니다. 이 경우에, 필터링된 정렬된 배열을 리턴하는 computed 프로퍼티를 만들 수 있다.
예를 들면:
const numbers = ref([1, 2, 3, 4, 5])
const evenNumbers = computed(() => {
return numbers.value.filter((n) => n % 2 === 0)
})
<li v-for="n in evenNumbers">{{ n }}</li>
computed 프로퍼티가 실현가능하지 않은 상황에(중첩된 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>
computed 프로퍼티에 reverse()와 sort()를 사용하는걸 주의하라! 이 두 메소드는 오리지널 배열을 상태변화시켜서, computed getters를 피할 수 있다. 이 메소드를 호출하기 전에 오리지널 배열의 복사본을 만들어라.
- return numbers.reverse()
+ return [...numbers].reverse()
'front > vue' 카테고리의 다른 글
[vue3 공식문서 번역]Essentials.9.Form Input Bindings (0) | 2022.04.25 |
---|---|
[vue3 공식문서 번역]Essentials.8.Event Handling (0) | 2022.04.23 |
[vue3 공식문서 번역]Essentials.6.Conditional Rendering (0) | 2022.04.21 |
[vue3 공식문서 번역]Essentials.5.Class and Style Bindings (0) | 2022.04.21 |
[vue3 공식문서 번역]Essentials.4.Computed Properties (0) | 2022.04.21 |
댓글