React(四)- ReactDOM的Diffing算法和React脚手架

本文深入探讨React中的key的作用及其在Diffing算法中的影响,解释为何在遍历列表时不应使用index作为key。同时,介绍了React脚手架的初始化过程和项目结构,展示了如何创建和使用简单的React组件,并提到了样式的模块化处理。通过实例,强调了正确选择key以提高渲染效率的重要性。
摘要由CSDN通过智能技术生成

React系列文章导航

一. React中的key

从案例出发,从key的角度来引入diffing算法案例1:

class Person extends React.Component {
    state = {
        persons: [
            { id: 1, name: '小张', age: 18 },
            { id: 2, name: '小李', age: 18 }
        ]
    }

    add = () => {
        const { persons } = this.state
        const p = { id: persons.length + 1, name: '小王', age: 20 }
        // 这里是小王置于前
        this.setState({ persons: [p, ...persons] })
    }

    render() {
        return (
            <div>
                <h1>人员列表</h1>
                <button onClick={this.add}>添加人员</button>
                <ul>
                    {
                        this.state.persons.map((p, index) => {
                            return <li key={index}>{p.name}----{p.age}</li>
                        })
                    }
                </ul>
            </div>
        )

    }
}
ReactDOM.render(<Person />, document.getElementById('test'))

页面效果如下:
在这里插入图片描述
点击添加人员按钮后:
在这里插入图片描述
我们可以从代码中提到两个问题:

  1. React中的key有什么作用?
  2. 为什么遍历列表的时候,key最好不要使用index

对于第一个问题,解答如下:

  1. key是虚拟DOM对象的标识,在更新显示的时候key起着非常重要的作用。
  2. 当状态中的数据发生变化时,React会根据 新数据 去生成 新的虚拟DOM
  3. 随后React会进行 新的虚拟DOM旧的虚拟DOMdiff比较,比较规则(也就是diffing算法)如下:

1.1 diffing规则

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

(1).若虚拟DOM中内容没变,那么直接使用之前的真实DOM
(2).若虚拟DOM中内容变了,那么生成新的真实DOM,随后替换掉页面中之前的真实DOM

B:旧虚拟DOM中若没有找到与新虚拟DOM相同的key

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


对于第二个问题,解答如下:

  1. 若对数据进行逆序添加逆序删除破坏顺序的操作会产生没有必要的真实DOM更新,执行效率低。
  2. 如果结构中还包含输入类的DOM,会产生错误DOM更新,页面显示会有问题。
  3. 若不存在上述情况,仅仅用于渲染列表的展示,那么使用index作为key是没问题的。

那么上述Demo中会有怎样的问题呢?来分析下:

初始数据以及初始的虚拟DOM:

数据:
{ id: 1, name: '小张', age: 18 },
{ id: 2, name: '小李', age: 18 }
虚拟DOM<li key=0>小张----18</li>
<li key=1>小李----18</li>

更新后的数据以及虚拟DOM:

{ id: 3, name: '小王', age: 20 },
{ id: 1, name: '小张', age: 18 },
{ id: 2, name: '小李', age: 18 }
虚拟DOM<li key=0>小王----20</li>
<li key=1>小张----18</li>
<li key=2>小李----18</li>

这里可以进行对比,发现原本的虚拟DOM更新后的虚拟DOM里面的key对应的内容全部对不上,那么根据以上规则:会将所有数据转化为真实DOM,并且渲染到页面。

即顺序打乱了,明明有两条数据的DOM可以作为复用,但是实际上导致了没有必要的虚拟DOM的更新。 那么如果数据有1W条,那么上述情况就会将1W条数据全部重新渲染,效率低下!

而从分析中我们可以发现,index也就是其标签索引,下标从0开始。

那么上述情况该怎么解决?我们可以用Id数据的唯一标识)作为key

this.state.persons.map((p) => {
    return <li key={p.id}>{p.name}----{p.age}<input type="text"/></li>
})

我们在原本代码的基础上增加一个输入框(见上面的代码),然后看看使用索引和数据唯一标识两种情况下的区别:

使用index作为key(提前往输入框中复制对应的属性)
在这里插入图片描述
点击添加后,可以发现数据对不上:
在这里插入图片描述


使用Id作为key:可以发现,数据能够对得上,也就佐证了上述的问题。
在这里插入图片描述

那么在实际开发的时候,我们如何去选择key

  • 最好使用每条数据的唯一标识作为key,比如Id、手机号、身份证号等。
  • 如果确定只是简单的展示数据,比如做一个Demo,那么使用index也是可以的(即不考虑效率的情况下

二. React脚手架

我们利用React脚手架来快速创建一个机遇React库的模板项目,其中:

  1. 包含了所有需要的相关配置(语法检查、jsx编译、devServer等)
  2. 下载好了所有相关的依赖。
  3. 可以直接运行一个简单效果。

React提供的脚手架库:create-react-app

项目的整体技术架构是:react+webpack+es6+eslint

2.1 初始化React脚手架

步骤如下:

  1. 全局安装npm install -g create-react-app
  2. 到自己想创建项目的目录,使用命令:create-react-app xxx
  3. 进入到对应的项目目录后启动即可:npm start

启动之后可以发现有如下提示信息:
在这里插入图片描述

2.2 脚手架文件介绍

在这里插入图片描述

public目录:静态资源文件夹

  • favicon.ico:网站页签图标
  • index.html主页面
  • logo02.png:logo图
  • logo512.png:logo图
  • manifest.json:应用加壳的配置文件
  • rebots.txt:爬虫协议文件

src目录:源码文件夹

  • App.css:App组件的样式
  • App.jsApp组件,所有组件的一个容器
  • App.test.js:用于给App做测试
  • index.css:样式
  • index.js入口文件
  • logo.svg:logo图
  • reportWebVitals.js:页面性能分析文件
  • setupTests.js:组件单元测试的文件

2.3 写一个简单的Hello组件

项目结构如下:
在这里插入图片描述
1.入口文件index.js

// 引入React核心库
import React from 'react'
// 引入ReactDOM
import ReactDOM from 'react-dom'
// 引入App组件
import App from './App'
// 渲染App到页面
ReactDOM.render(<App />, document.getElementById('root'))

2.外壳文件App.js:(其他定义的组件都放在这里)

// 创建外壳组件App
import React, { Component } from 'react'
import Hello from './component/Hello/Hello'
import World from './component/World/World'

// 暴露App组件,其他Js就可以引用了
export default class App extends Component {
    render() {
        return (
            <div>
                <Hello/>
                <World/>
            </div>
        )
    }
}

3.以Hello组件为例,Hello.js:组件js一般都以大写开头(和普通js文件进行区分)

import React, { Component } from 'react'
import './Hello.css'

export default class Hello extends Component {
    render() {
        return (
            <h2 className="title">Hello</h2>
        )
    }
}

4.对应的css文件:

.title{
    background-color: rgb(167, 157, 20);
}

5.运行结果如下:
在这里插入图片描述


Tip1:为了更加直观的区分,可以把组件的文件都改为.jsx结尾,此时对应的文件图标也会改变哦~
在这里插入图片描述


Tip2:每个组件一般都有自己的专属文件夹,那么直接将组件的名字改为index.jsx即可:(这种方式并不推荐,因为最好将每个组件都定义一个名字,更加规范)
在这里插入图片描述
若改为这种形式,那么App.js中进行引入的时候,就不需要引入到具体的文件了:
在这里插入图片描述

2.3.1 样式的模块化

改变如下:css文件的名字加一个module
在这里插入图片描述
引用的时候改为:
在这里插入图片描述

Tip3:VsCode快捷创建组件
在该目录下创建一个Test.jsx文件:
在这里插入图片描述
直接输入rcc,回车即可:
在这里插入图片描述
则代码自动生成:
在这里插入图片描述


文章结尾预告:,下一篇文章准备从功能界面的组件化编码流程来讲,也就是如何将多个组件进行组合使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值