先分享两个经典面试题:
下面就从针对这两个面试题来了解 key 的作用。
key 是虚拟 DOM 对象的标识,在更新显示时 key 起着极其重要的作用。
当状态中的数据发生变化时,React 会根据【新数据】生成【新的虚拟 DOM】,随后 React 进行【新虚拟 DOM】与【旧虚拟 DOM】的 diff 比较。
比较规则如下:
- 旧虚拟 DOM 中找到了与新虚拟 DOM 相同的 key:
- 如果虚拟 DOM 中内容没变,则直接使用之前的真实 DOM;
- 如果虚拟 DOM 中内容变了,则生成新的真实 DOM,随后替换掉页面中之前的真实 DOM。
- 旧虚拟 DOM 中未找到与新虚拟 DOM 相同的 key:
- 根据数据创建新的真实 DOM,随后渲染到页面。
上图中,逆序添加数据后,使得整个列表数据的 index 全部更新,导致旧虚拟 DOM 和新虚拟 DOM 中 key 对应的节点都需要重新生成真实。但数据量很大时,会引发很大效率问题。
上图中,添加和修改数据后,旧虚拟 DOM 和新虚拟 DOM 中 key 对应的节点内容无更新则无需重新生成真实 DOM (上图中的 小张 );只对新增或被修改的虚拟 DOM 节点生成真实 DOM 并重新渲染。对比 index 索引值作为 key 的案例,使用 id 作为 key 则大大提高了效率。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>key 的作用</title>
</head>
<body>
<!-- 准备好一个容器 -->
<div id="app"></div>
<!-- step01: 引入react核心库 -->
<script type="text/javascript" src="../js/17/react.development.js"></script>
<!-- step02: 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/17/react-dom.development.js"></script>
<!-- step03: 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel"> /* 此处一定要写babel */
class Person extends React.Component {
state = {
persons: [
{id: 1, name: '小张', age: 18},
{id: 2, name: '小李', age: 19},
]
}
add = () => {
const {persons} = this.state
const p = {id: persons.length + 1, name: '小王', age: 20}
this.setState({persons: [p, ...persons]})
}
render() {
return (
<div>
<h2>展示人员信息</h2>
<button onClick={this.add}>添加一个小王</button>
<h3>使用 index 索引值作为 key</h3>
<ul>
{
this.state.persons.map((personObj, index) => {
return <li key={index}>{personObj.name} ---- {personObj.age} <input type="text"/></li>
})
}
</ul>
<h3>使用 id 数据的唯一标识作为 key</h3>
<ul>
{
this.state.persons.map((personObj, index) => {
return <li key={personObj.id}>{personObj.name} ---- {personObj.age} <input type="text"/></li>
})
}
</ul>
</div>
)
}
}
ReactDOM.render(<Person/>, document.getElementById('app'));
</script>
</body>
</html>