React之DOM的diff算法

Posted Icy Hunter

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React之DOM的diff算法相关的知识,希望对你有一定的参考价值。

文章目录

DOM的diff算法

React展示前端首先将DOM转换为虚拟DOM,然后再生成页面上的真实DOM,因此当DOM更新时,React会先更新虚拟DOM,然后将新的虚拟DOM与旧的进行对比,如果遇到相同的,页面上对应的DOM就不需要变动,如果遇到不相同的,那么就更新对应页面上的DOM。

这样的好处就是当一个页面内容很多,但是每次只需要更新一点点内容时,React就会有比较好的性能。

react中的key有什么作用?

虚拟DOM中key的作用:

1) 简单的说:key是虚拟DOM对象的标识,在更新显示时key起着极其重要的作用。、
2) 详细的说:当状态中的数据发生变化时,react会根据新数据生成新的虚拟DOM,随后React进行新虚拟DOM与旧虚拟DOM的diff比较比较规则如下:
a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
(1). 若虚拟DOM中的内容没变,直接使用之前的真实DOM
(2). 若虚拟DOM中的内容变了,则生成真实DOM,随后替换掉页面中之前的真实DOM
b. 旧虚拟DOM中未找到与新虚拟DOM相同的key,根据数据创建新的真实DOM,随后渲染到网页。

为什么遍历列表时,key最好不要用index?

用index作为key可能会引发的问题:

1)若对数据进行:逆序添加、逆序删除等破环顺序操作,会产生没有必要的真实DOM更新 界面效果没问题,单效率低
2) 如果结构中还包含输入类的DOM,会产生错误DOM更新界面有问题
3) 注意!如果不存在对数据逆序添加、逆序删除等破环顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。

开发中如何选择key?

1.最好使用每条数据唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
2.如果确定只是简单的展示数据,用index也是可以的

实例

用个实例来感受一下。

假设这里是逆序添加元素,就会导致一些问题:

<!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>Document</title>
</head>
<body>
    <div id="test"></div>

    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
    <script src="../js/prop-types.js"></script>
    <script type="text/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>
                    <hr/>
                    <hr/>
                    <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("test"))
    </script>
</body>
</html>

运行后

页面文本框输入对应的信息,然后点击按钮


发现逆序添加元素时

用index会导致错位,因为
index原本是 小张0,小李1,现在逆序添加小王,那么现在小王为0,小张1,小李2,导致DOM得重新生成,而输入框的内容并未改变,则保留,就会导致这样的错误。

但是如果顺序添加元素,这个实例其实也没什么问题:

<!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>Document</title>
</head>
<body>
    <div id="test"></div>

    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
    <script src="../js/prop-types.js"></script>
    <script type="text/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:[...persons,p])
            
            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>
                    <hr/>
                    <hr/>
                    <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("test"))
    </script>
</body>
</html>

运行结果:

总结

所有还是需要将key设置为唯一标识,不能简单用index,因为可能到时候会出现bug。

以上是关于React之DOM的diff算法的主要内容,如果未能解决你的问题,请参考以下文章

前端学习(3150):react-hello-react之DoM的diff算法

什么是diff算法?

什么是diff算法?

react虚拟dom与diff算法

React的虚拟DOM与diff算法的理解

React diff 算法与其他框架对比