Vue - 리스트 렌더링

김영준·2023년 8월 1일
0

TIL

목록 보기
52/91
post-thumbnail

배열

v-for을 통해서 요소를 반복해서 출력할 수 있다.

<li v-for="item in items">
	{{ item.message }}
</li>

현재 항목의 인덱스를 두 번째 전달인자 옵션으로 제공한다.

<li v-for="(item, index) in items">
	{{ index }} - {{ item.message }}
</li>

in 대신에 of를 구분자로 사용할 수 있다.
JavaScript의 이터레이터 구문과 유사하다.

<div v-for="item of items"></div>

객체

객체의 속성을 반복 (value를 반복)

<ul>
	<li v-for="value in myObject">
    	{{ value }}
    </li>
</ul>

key에 대한 두번째 전달 인자를 제공한다.

<ul>
	<li v-for="(value, key) in myObject">
    	{{ key }}: {{ value }}
    </li>
</ul>

세번째 전달 인자로는 index를 제공한다.

<ul>
	<li v-for="(value, key, index) in myObject">
    	{{ index }}. {{ name }}: {{ value }}
	</li>
</ul>

객체를 반복할 때는 순서를 보장할 수 없다.


v-for 디레틱브를 사용할 때는 항상 key 속성을 사용하여 고유한 값을 지정해주어야 한다.

<div v-for="item in items" :key="item.id">
	<!-- content -->
</div>

배열이 반응형 데이터면 변이 메소드를 사용해서 배열이 변경된 것을 감지할 수 있고 화면을 갱신할 수 있다.

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

filter(), concat(), slice()와 같은 원래 배열을 변경하지는 않지만 항상 새 배열을 반환하는 비-변이 메소드가 있다.

example.items = example.items.filter(item => item.message.match(/Foo/))

이 메소드를 사용할 시 기존 DOM을 버리고 전체 목록을 다시 렌더링 할 것이라고 생각할 수 있지만 그렇지 않다.
Vue는 이전 배열과 현재 배열의 차이점을 비교해서 변경된 데이터만 다시 화면에 출력한다. (최적화)


v-for에서 computed 데이터를 사용해도 마찬가지로 변경된 데이터만 리렌더링한다.

<li v-for="n in evenNumbers">{{ n }}</li>

<script>
data() {
	return {
    	numbers: [ 1, 2, 3, 4, 5 ]
        }
    },
computed: {
	evenNumbers() {
    	return this.numbers.filter(number => number % 2 === 0)
    }
}
</script>

computed 속성이 실행 가능하지 않은 상황에서는 메소드를 사용할 수 있다.

<ul v-for="numbers in sets">
	<li v-for="n in even(numbers)>{{ n }}</li>
</ul>

<script>
data () {
	return {
    	sets: [[ 1, 2, 3, 4, 5 ], [ 6, 7, 8, 9,10 ]]
    }
},
methods: {
	even(numbers) {
		return numbers.filter(number => number % 2 === 0)
    }
}
</script>

v-for도 정수를 사용할 수 있다. 이 경우 템플릿을 여러 번 반복한다.
(0이 아닌 1부터 시작)

<div>
	<!-- 12345678910 -->
	<span v-for="n in 10">{{ n }}</span> 
</div>

v-if와 마찬가지로, v-for와 함께 <template> 태그를 사용하여 여러 요소의 블록을 렌더링 할 수도 있다.

<ul>
	<template v-for="item in items">
		<li>{{ item.msg }}</li>
    	<li></li>
	</template>
</ul>

컴포넌트의 v-for

components 옵션: 외부에 다른 컴포넌트를 정의
emit(이름, 전달할 인수): 커스텀 이벤트 지정

예제

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <form @submit="addNewTodo">
        <label for="new-todo">Add a todo</label>
        <input id="new-todo" v-model="newTodoText" placeholder="E.g. Feed the cat" />
        <button>Add</button>
      </form>
      <ul>
        <todo-item v-for="todo in todos" :key="todo.id" :todo="todo" @remove="removeTodo" />
      </ul>
    </div>
    <script>
      function generateId() {
        return `${Date.now()}${Math.random()}`;
      }
      const TodoItem = {
        template: `
        <li>
          {{ todo.title }}
          <button @click="$emit('remove', todo.id)">Remove</button>
        </li>
        `,
        props: ["todo"], // todo를 컴포넌트 내부에서 사용
      };
      const App = {
        components: {
          TodoItem, // 컴포넌트를 정의
        },
        data() {
          return {
            newTodoText: "",
            todos: [],
          };
        },
        methods: {
          addNewTodo(event) {
            event.preventDefault();
            this.todos.push({
              id: generateId(),
              title: this.newTodoText,
            });
            this.newTodoText = "";
            console.log(this.todos);
          },
          removeTodo(todoId) {
            // Vue는 내용을 비교하고 다른 점만 새로 갱신
            this.todos = this.todos.filter((todo) => {
              return todo.id !== todoId;
            });
          },
        },
      };
      const vm = Vue.createApp(App).mount("#app");
    </script>
  </body>
</html>
profile
꾸준히 성장하는 개발자 블로그

0개의 댓글