vue에서 v-for를 사용할 때 왜 index를 키로 사용할 수 없나요? 다음 글에서는 v-for의 핵심값이 index가 될 수 없는 이유를 소개하겠습니다. 도움이 되셨으면 좋겠습니다!
많은 사람들이 이런 흔한 면접 질문을 하면 바로 가상 DOM
과 diff 알고리즘
에 대해 이야기하기 시작합니다. 虚拟DOM
和 diff算法
了。
讲这些没问题,但如果是我,一定先讲 v-for 的 key 值写成 index 会造成的问题,再讲原理。
曾经我写 v-for, key 值永远都是 index,直到有一天,我这么写造成了线上bug...
来看一下我的线上bug演示吧:
父组件代码 <Child v-for="(item, index) in list" :key="index" :count="item.count" :name="item.name" @delete="handleDelete(index)" /> list: [ { count: 1, name: '第1个元素' }, { count: 2, name: '第2个元素' }, { count: 3, name: '第3个元素' } ] handleDelete(index) { this.list.splice(index, 1) },
如代码和gif演示,点击删除第2个元素,看上去似乎一切正常。
等一下,第三个元素的count值居然变成了2,wtf!!!
惊得我又去看了遍子组件的代码
子组件 <div> <span>{{ name }}</span> count值为:{{ innerCount }} <button @click="$emit('delete')">-</button> </div> props: { count: { type: Number, default: 0 }, name: { type: String, default: '' } }, data() { return { innerCount: this.count } }
感觉也没什么不对的啊。
不信邪,我又多创建了点元素来删除,还试了下排序:
果然,不光删除元素有问题,排序也有问题。
把 key 值改成 item.name 再试一下。
<Child v-for="(item, index) in list" :key="item.name" :count="item.count" :name="item.name" @delete="handleDelete(index)" />
正常了。
这样看来,在 v-for 里把 key 值写成 index,非常危险啊。
在查阅了 vue 官方文档之后,我终于明白了原因:
当 Vue 正在更新使用
v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
不依赖子组件状态
子组件里有一行很关键的代码
data() { return { innerCount: this.count } }
子组件内部定义了 innerCount,这样子组件就有了自己的状态,按照官方文档的说明,这种情况下不能把 index 作为 key 值。
临时 DOM 状态
<div v-for="(item, index) in list1" :key="index"> <input type="text" /> <button @click="delClick(index)">删除</button> </div>
删除了第2项,但是第3项在表单中的3变成了2,跟上面依赖子组件状态的例子是一样的。
写列表渲染时, 依赖子组件状态或临时 DOM 状态的情况,如果有 删除、增加、排序这样的功能,不要把 index 作为 key。
事实上,写列表渲染时,永远不要把 index 做为 key,key 一定要是唯一标识。
至于原因,就要理解 diff
너무 놀라서 다시 서브컴포넌트의 코드를 살펴보니rrreee
아무 문제가 없다는 걸 느꼈습니다. 🎜🎜나는 악을 믿지 않기 때문에 삭제할 요소를 더 만들고 정렬을 시도했습니다: 🎜🎜🎜🎜물론 요소 삭제 문제 뿐만 아니라 정렬 문제도 있습니다. 🎜🎜키 값을 item.name으로 변경하고 다시 시도하세요. 🎜rrreee🎜🎜🎜 정상입니다. 🎜🎜v-for에서 키값을 인덱스로 쓰는 것은 매우 위험한 것 같습니다. 🎜🎜공식 Vue 문서를 참조한 후 마침내 이유를 이해했습니다. 🎜🎜Vue가 v-for
를 사용하여 렌더링된 요소 목록을 업데이트할 때 기본적으로 "내부 업데이트"를 사용합니다. 전략. 데이터 항목의 순서가 변경되면 Vue는 데이터 항목의 순서와 일치하도록 DOM 요소를 이동하지 않지만 각 요소를 제자리에 업데이트하고 각 인덱스 위치에서 올바르게 렌더링되도록 합니다. 🎜
🎜이 기본 모드는 효율적이지만 🎜하위 구성 요소 상태나 임시 DOM 상태(예: 양식 입력 값)에 의존하지 않는 목록 렌더링 출력🎜에만 적합합니다. 🎜🎜🎜하위 구성 요소의 상태에 의존하지 않습니다🎜🎜🎜하위 구성 요소에 매우 중요한 코드 줄이 있습니다🎜rrreee🎜innerCount는 하위 구성 요소에서 내부적으로 정의되므로 하위 구성 요소는 자체 상태를 갖습니다. 공식 문서에 따르면 이 경우 index를 키 값으로 사용할 수 없습니다. 🎜🎜🎜임시 DOM 상태🎜🎜rrreee🎜🎜🎜두 번째 항목은 삭제되지만 양식의 세 번째 항목은 2가 됩니다. 이는 위의 하위 구성 요소 상태에 의존하는 예와 같습니다. 🎜
diff
알고리즘을 이해해야 합니다. 🎜🎜답변할 질문: 🎜🎜🎜왜 키를 임의의 숫자나 타임스탬프로 쓸 수 없나요? 🎜🎜Key 왜 고유 식별자여야 합니까? 🎜🎜🎜걱정하지 마세요. Vue 이슈와 관련된 글 100개를 작성하도록 플래그를 설정해 두었으니 다음 글에서 천천히 분석해 보겠습니다. 🎜🎜제 Vue 시리즈 기사가 프런트엔드 분야에서 여러분에게 도움이 되기를 바랍니다~🎜🎜[관련 추천: 🎜vue.js 비디오 튜토리얼🎜]🎜위 내용은 v-for 지시문의 키 값이 vue의 색인이 될 수 없는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!