Vue는 메모리를 아끼기 위해서 DOM 최적화를 통해 DOM을 재사용 한다. 이 과정에서in-place patch전략이라는 것을 사용한다. patch는 일종의 "땜빵" 을 의미하고 in-place는 현재 지점에서를 의미하니까 in-place patch 전략이란 현재 DOM에서 바뀌어야할 부분만 땜빵해서 처리하고 DOM을 재사용한다는 내용이다.
이 전략은 당연히 DOM 재사용 측면에서 매우 우수한데 가끔 문제를 일으키기도 한다.
언제가 문제인고 하니..
예를 들어 유니크한 과일의 목록을 리스트로 관리하고 과일의 개수를 지정해서 구매한다고 생각해보자.
<body>
<div id="app">
<ul>
<li v-for="item in list">
{{item}} : <input type="number" /> 개
</li>
</ul>
</div>
</body>
<script src="https://unpkg.com/vue@3"></script>
<script>
const app = Vue.createApp({
setup(props) {
// 과일의 목록은 중복되지 않는다.
const list = Vue.ref(["apple", "banana", "orange"]);
return {
list,
};
},
}).mount("#app");
</script>
위 코드는 잘 동작하며 apple 1개, banana 2개, orange 3개를 구매할 수 있다.
여기서 눈여겨볼 내용은 반복되는 <li>태그의 구성이다. <li>에는 {{item}} 이라는 표현식과 함께 일반 태그인 <input>이 있고 여기에 과일의 개수가 저장된다.
여기서 배열의 순서가 바뀌면?
이 상태에서 배열의 순서를 apple, banana, orange에서 banana, orange, apple로 변경하면 어떻게 되어야 할까? 당연히 우리의 기준으로는 apple 1개라는 <li>태그 자체가 이동하는게 맞지만 vue는 in-place patch로 처리하기 때문에 {{item}} 부분만 살짝 patch 하고 만다.
만약 <li>의 내용이 {{item}}으로만 구성되어있었다면 전혀 문제가 되지 않지만 다른 내용과 함께 사용된다면 문제가 될 수 있는 것이다.
반복되는 내용을 하나로 관리하기 위해서 key 필요
위와 같은 문제를 방지하기 위해 반복되는 내용을 하나로 관리할 필요가 있고 이때 사용되는 것이 key이다. key에는 요소를 구별할 수 있는 unique 한 내용을 사용해야 한다.
특히 list의 요소를 index로 구분한다고 해서 index를 사용하면 안된다. index는 요소에 속한 값이 아니고 그때 그때 바뀌는 값이기 때문이다. 요소 자체로 구별될 수 있는 값이어야 하기 때문에 [{id:1, name:'apple'}, {id:2, name:'banana'}] 형태로 작성하고 id를 key로 사용하거나 이 예제에서 처럼 list 안의 요소들을 unique 하게 설정할 수도 있다.