React学习笔记(四)

185 阅读6分钟

一.虚拟DOM与 DOM Diffing算法

1.验证DOM Diffing算法

废话不多说,先来看这样一个案例:

class Time extends React.Component{
        state={
            date:new Date()
        }

        componentDidMount(){
            setInterval(()=>{
                this.setState({date : new Date()})
            },1000)
        }

        render(){
            return(
                <div>
                    <span>Hello,
                    <input type="text" />
                    <h2>!It is:{this.state.date.toTimeString()}
                        <input type="text" />
                    </h2>
                    时间每隔一秒刷新一次 而h1和input标签不变化不重新渲染 所以在页面input中输入内容不被清空
                </span>
                </div>
            )
        }
    }
    ReactDOM.render(<Time />,document.getElementById('test'))

结果如图:

验证Diffing算法图.gif

2.1 key的作用

举个例子:

在一个组件中,我们先创建了两个对象,通过循环的方式放入<li>标签中,此时key使用的是index

如果生成的render出来后就不会改变里面的内容,那么你不需要指定key(不指定key时,React也会生成一个默认的标识),或者将index作为key,只要key不重复即可。

但是如果你的标签是动态的,是有可能刷新的,就必须显示的指定key。必须上面案使用map进行便利的时候就必须指定Key:

this.state.num.map((n,index)=>{
    return <div className="news" key={index} >新闻{n}</div>
})

这个地方虽然显示的指定了key,但是官网并不推荐使用Index作为Key去使用;

这样会很有可能会有效率上的问题 举个例子:

在一个组件中,我们先创建了两个对象,通过循环的方式放入<li>标签中,此时key使用的是index

person:[
    {id:1,name:"张三",age:18},
    {id:2,name:"李四",age:19}
]
​
this.state.person.map((preson,index)=>{
    return  <li key = {index}>{preson.name}</li>
})

如下图展现在页面中:

1611800406864.png

此时,我们想在点击按钮之后动态的添加一个对象,并且放入到li标签中,在重新渲染到页面中。

我们通过修改State来控制对象的添加。

<button onClick={this.addObject}>点击增加对象</button>
addObject = () =>{
    let {person} = this.state;
    const p = {id:(person.length+1),name:"王五",age:20};
    this.setState({person:[p,...person]});
}

如下动图所示:

addObject.gif

这样看,虽然完成了功能。但是其实存在效率上的问题, 我们先来看一下两个前后组件状态的变化:

我们发现,组件第一个变成了王五,张三和李四都移下去了。因为我们使用Index作为Key,这三个标签的key也就发生了改变【张三原本的key是0,现在变成了1,李四的key原本是1,现在变成了2,王五变成了0】在组件更新状态重新渲染的时候,就出现了问题:

1611800988496.png 因为react是通过key来比较组件标签是否一致的,拿这个案例来说:

  • 首先,状态更新导致组件标签更新,react根据Key,判断旧的虚拟DOM和新的虚拟DOM是否一致
  • key=0的时候 旧的虚拟DOM 内容是张三 新的虚拟DOM为王五 ,react认为内容改变,从而重新创建新的真实DOM.
  • key=1的时候 旧的虚拟DOM 内容是李四,新的虚拟DOM为张三,react认为内容改变,从而重新创建新的真实DOM
  • key=2的时候 旧的虚拟DOM没有,创建新的真实DOM

这样原本有两个虚拟DOM可以复用,但都没有进行复用,完完全全的都是新创建的;这就导致效率极大的降低。

其实这是因为我们将新创建的对象放在了首位,如果放在最后其实是没有问题的,但是因为官方并不推荐使用Index作为key值,我们推荐使用id作为key值。从而完全避免这样的情况。

2.1基本原理图

11.png

3.关于key的经典面试题

  • react/vue中的key有什么作用?(key的内部原理是什么?)
  • 为什么遍历列表时,key最好不要用index?

4.1.1 虚拟DOM中key的作用

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

  • 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较,比较规则如下:

    • 旧虚拟DOM中找到了与新虚拟DOM相同的key:

      • 若虚拟DOM中内容没变, 直接使用之前的真实DOM
      • 若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
    • 旧虚拟DOM中未找到与新虚拟DOM相同的key

      • 根据数据创建新的真实DOM,随后渲染到到页面

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

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

4.1.3 开发中如何选择key?

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

二.React脚手架

2.1 使用 create-react-app 创建 react 应用

2.1.1 react脚手架

  • 1.xxx脚手架:用来帮助程序员快速创建一个基于xxx库的模板项目

    • 1.包含了所有需要的配置(语法检查、jsx编译、devServer...)
    • 2.下载好了所有相关的依赖
    • 3.可以直接运行一个简单效果
  • 2.react提供了一个用于创建react项目的脚手架军: create-react-app

  • 3.项目的整体技术架构为: react + webpack + es6 + eslint

  • 4.使用脚手架开发的项目的特点:模块化,组件化,工程化

2.1.2 创建项目并启动

  • 第一步,全局安装:npm i -g create-react-app
  • 第二步,切换到想创项目的目录,使用命令:create-react-app <project-name>
  • 第三步,进入项目文件夹:cd <project-name>
  • 第四步,启动项目:npm start

2.1.2 react脚手架项目结构

  • 我们主要来看看publicsrc整两个目录

  • public 1611817630266.png

  • src

1611818262317.png

  • 完整目录结构如下:
|-node_modules ----- npm下载的相关依赖 
|-public ----- 静态资源文件夹
|   -css ------  css静态样式文件夹
|   -favicon.icon ----- 网站页签图标
|   -index.html -----   主页面
|   -logo192.png ------- logo图
|   -logo512.png ------- logo图
|   -manifest.json -----  应用加壳的配置文件
|   -robots.txt -------- 爬虫协议文件
|-src ----源码文件夹
|   -App.css -------- App 组件的样式
|   -App.js--------- App组件
|   -App.test.js ----用于给App做测试
|   -index.css ------样式
|   -index.js.-----入口文件
|   -logo.svg.------- logo图
|   -reportWebMitals.js.
|-package.json --- node包文件 包括项目的一些介绍 以及 相关文件版本
|-package.lock --- 依赖文件锁文件
|-README.md 自述文件

3.1.3 运行项目

执行npm run start后,看到这个页面,就说明项目运行成功了!!

1611816150630.png

三.参考

React官网: react.docschina.org/

尚硅谷视频: www.bilibili.com/video/BV1wy…