小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。
验证 Diffing 算法
class Time extends React.Component {
state = {date: new Date()}
componentDidMount() {
setInterval(() => {
this.setState({date: new Date()})
}, 1000)
}
render() {
return (
<div>
<h1>hello</h1>
<input type="text"/>
<span>现在是:{this.state.date.toTimeString()}</span>
</div>
)
}
}
ReactDOM.render(<Time/>, document.getElementById("test"));
复制代码
由上述案例可以看出,span 标签里面的时间每隔一秒就进行更新,可以通过在 input 标签里输入的方式证明 input 标签并为随着 span 标签更新而更新。因此:Diffing 算法对比的最小粒度是节点。
遍历列表时的 key
经典面试题:
- React/Vue 中的 key 有什么作用?key 内部原理是什么?
- 为什么遍历列表时,key 最好不要用 index?
/**
【使用 index 索引值 作为 key】
初始数据:
{id: 1, name: '小张', age: 18}
{id: 2, name: '小李', age: 19}
初始的虚拟 DOM:
<li key=0>小张 --- 18</li>
<li key=1>小李 --- 19</li>
更新后的数据:
{id: 3, name: '小王', age: 20}
{id: 1, name: '小张', age: 18}
{id: 2, name: '小李', age: 19}
更新数据后的虚拟 DOM:
<li key=0>小王 --- 20</li>
<li key=1>小张 --- 18</li>
<li key=2>小李 --- 19</li>
由于 index 不同,导致小张、小李都没有被复用,效率变低。
----------------------------------------------
【使用 id 唯一标识做为 key】
初始数据:
{id: 1, name: '小张', age: 18}
{id: 2, name: '小李', age: 19}
初始的虚拟 DOM:
<li key=1>小张 --- 18</li>
<li key=2>小李 --- 19</li>
更新后的数据:
{id: 3, name: '小王', age: 20}
{id: 1, name: '小张', age: 18}
{id: 2, name: '小李', age: 19}
更新数据后的虚拟 DOM:
<li key=3>小王 --- 20</li>
<li key=1>小张 --- 18</li>
<li key=2>小李 --- 19</li>
小张、小李被复用,效率提高。
**/
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) => {
return (
<li key={personObj.id}>
{personObj.name} --- {personObj.age}
<input type="text" />
</li>
);
})}
</ul>
</div>
);
}
}
ReactDOM.render(<Person />, document.getElementById("test"));
复制代码
- 虚拟 DOM 中 key 的作用:
- 简单地说:key 是虚拟 DOM 对象的标识,在更新显示时起着极其重要的作用。
- 详细地说:当状态中的数据发生变化时,React 会根据新数据生成新的虚拟 DOM,随后 React 进行新虚拟 DOM 与旧虚拟 DOM 进行 Diff 比较,规则如下:
旧虚拟 DOM
中找到了与新虚拟 DOM
相同的 key:- 若
虚拟 DOM
中内容没变,直接使用之前的真实 DOM
。 - 若
虚拟 DOM
中内容变了,则生成新的真实 DOM
,随后替换掉页面中之前的真实 DOM
。
- 若
旧虚拟 DOM
中未找到与新虚拟 DOM
相同的 key:- 根据数据创建新的真实 DOM,随后渲染到页面。
- 用 index 作为 key 可能会引发的问题:
- 若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实 DOM 更新 ---> 界面效果没问题但效率低。
- 如果结构中还包含输入类 DOM:会产生错误 DOM 更新 ---> 界面有问题
- 注意:如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用 index 作为 key 时没有问题的。
- 开发中如何选择 key:
- 最好使用每条数据的唯一标识作为 key,比如 id、手机号、身份证号、学号等唯一值。
- 如果确定只是简单的展示数据,用 index 也是可以的。