每天学点React - DOM的Diffing算法简单验证

124 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天,点击查看活动详情

DOM的Diffing算法

验证Diffing算法

为了验证React的Diffing算法是否存在,我们需要写一个小案例来验证一下。首先,在页面中定义一个h1标签,一个input标签,还有一个span标签三个,在span标签中,我们将当前的时间点动态进行实时显示,效果如下图所示: image.png

案例代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>验证Diffing算法</title>
</head>
<body>
    <!-- 测试容器 -->
    <div id="test"></div>

    <!-- 加载 React 核心库 -->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- 加载 React DOM 用于支持 React 操作 DOM -->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 加载 babel 用于将 jsx 转为 js -->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    

    <script type="text/babel">
        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'))
    </script>
</body>
</html>

基础的功能写完了,那么我们需要如何验证呢?其实要验证很简单的,因为Diffing算法的最小粒度是标签,如果标签被从新render的话,那么里面的内容也会被清除的,我们只需要在input输入内容,然后看看会不会被span标签的时间更新时清除掉即可。

image.png

image.png

从上面的两张图可以看出,input标签的内容并没有被清除,那么,我们再来看看,如果在span标签中嵌套多一个input,那该标签的内容会不会被清除呢,让我们来看一下吧

render() {
    return (
        <div>
            <h1>hello</h1>
            <input type='text' />
            <span>
                现在是北京时间:{this.state.date.toTimeString()}
                <input type='text' />
            </span>
        </div>
    )
}

image.png

image.png

效果图可以看出,span标签中的内容也没有被清除,看来Diffing算法也有递归检查标签嵌套的,通过比较发现两个标签一样,就没替换掉原先的标签,省略了重新渲染的步骤。

key的作用

经典面试题:

  1. react/vue中的key有什么作用?(key的内部原理是什么?)

    1)简单说明:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。

    2)详细补充:当状态中的数据发生变化时,React会根据【新数据】生成新的虚拟DOM,随后React会将【新/旧虚拟DOM】的diff进行比较,比较规则如下:

     a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
         - 若虚拟DOM中内容没变,直接使用之前的真实DOM
         - 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
     b. 旧虚拟DOM中未找到与新虚拟DOM相同的`key`,则根据数据创建新的真实DOM,随后渲染到页面
     
    
  2. 为什么遍历列表时,key最好不要用index?

    1)若对数据进行:逆序添加、逆序删除等破坏顺序操作,会产生没有必要的真实DOM更新,不会影响页面效果,但是降低效率

    2)如果结构中还包含输入类的DOM,会产生错误DOM更新,导致界面渲染异常

  3. 开发中如何选择key?

    1)最好使用每条数据的唯一标识来作为key,比如:id、手机号码等

    2)如果确定只是简单的展示数据,用index也是可以的