React学习笔记

学习来源:尚硅谷

学习时间:2022年3月30日

版本:16.8

1 简介

React用于构建用户界面的JS库,是一个将数据渲染为HTML视图的开源JS库。

1.1 原生js的痛点

  1. 原生JS操作DOM繁琐,效率低
  2. 使用JS直接操作DOM,浏览器会进行大量的重绘重排
  3. 原生JS没有组件化编码方案,代码复用低

1.2 react的特点和优势

特点

  1. 声明式编码
  2. 组件化编码
  3. React Native 编写原生应用
  4. 高效(优秀的Diffing算法)

高效的原因

  1. 使用虚拟(virtual)DOM,不总是直接操作页面真实DOM。
  2. DOM Diffing算法,最小化页面重绘。

原生js和react比较

  • 原生js

image-20220330150202284

  • React:数据更新时,虚拟dom比较有差异的部分,再将其渲染到真实dom上

image-20220330150225381

2 基本使用

2.1 入门案例

  • 引入js相关的库

    • react.js:React核心库。全局会引入React变量。
    • react-dom.js:提供操作DOM的react扩展库。全局会引入ReactDOM变量
    • babel.min.js:解析JSX语法代码转为JS代码的库。此外,模块化语法转化、ES6转换为ES5也需要。
    • 注意引入顺序:先引入react.development.js,后引入react-dom.development.js
  • 创建项目文件夹,将上述资源文件放置在js目录下:

image-20220330152456583

  • 新建页面hello.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</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 -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel"> /* 此处一定要写babel */
// 1.创建虚拟dom
const VDOM = <h1>Hello React</h1>; /* 此处不要写引号,因为不是字符串 */
// 2.渲染虚拟dom到页面
ReactDOM.render(VDOM, document.getElementById("test"));
</script>
</body>
</html>

注意点详见注释。

执行结果

image-20220330152625697

可见虚拟dom中的h1标签已经挂载到了真实dom中的div容器中。

2.2 创建虚拟dom的方式

  • 方式1:使用JSX创建虚拟DOM,即入门案例
1
2
3
4
5
const VDOM = (
<h1 id="title">
<span>Hello React</span>
</h1>
);
  • 方式2:使用js创建虚拟dom,一般不用,多层结构会导致代码繁琐
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用JS创建虚拟DOM</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>

<script type="text/javascript">
// 1.创建虚拟dom
// React.createElement(标签名, 标签属性, 标签内容)
const VDOM = React.createElement("h1", {id: "title"}, React.createElement("span", {}, "Hello React"));
// 2.渲染虚拟dom到页面
ReactDOM.render(VDOM, document.getElementById("test"));
</script>
</body>
</html>

执行结果

image-20220330154048302

使用JS和JSX都可以创建虚拟DOM,但是可以看出JS创建虚拟DOM比较繁琐,尤其是标签嵌套如果很多的情况下,所以还是比较推荐使用JSX来创建。

2.3 虚拟dom和真实dom

  • 本质是Object类型的对象(一般对象)
  • 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性
  • 虚拟DOM最终会被React转换为真实DOM,渲染在页面上

代码演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>虚拟dom和真实dom</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id="test"></div>
<div id="demo"></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 -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel"> /* 此处一定要写babel */
// 1.创建虚拟dom
const VDOM = (
<h1 id="title">
<span>Hello React</span>
</h1>); /* 此处不要写引号,因为不是字符串 */
// 2.渲染虚拟dom到页面
ReactDOM.render(VDOM, document.getElementById("test"));
const TDOM = document.getElementById("demo");
console.log("虚拟dom", VDOM);
console.log("真实dom", TDOM);
console.log(typeof VDOM); // Object
console.log(VDOM instanceof Object); // true
</script>
</body>
</html>

image-20220330155127003

2.4 JSX语法

2.4.1 语法规则

JSX全称: JavaScript XML,是react定义的一种类似于XML的JS扩展语法。

JSX本质是React.createElement(component, props, ...children)方法的语法糖

语法规则

  • 定义虚拟DOM时,不要写引号

  • 标签中混入JS表达式的时候使用{},一定注意区分js语句(代码)js表达式的区别

    • 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方,下面的例子都是表达式
      • a
      • a + b
      • demo(1)
      • arr.map()
      • function test () { //... }
    • 语句(代码):
      • if(){ //... }
      • for(){ //... }
      • switch(){ case:... }
  • 样式的类名不要用class,而是用className

  • 内联样式要使用style={{key1: value1, key2: value2...}}的形式
  • 虚拟DOM只能有一个根标签,常用<div>将整个标签包裹起来,里面再写子标签
  • 标签必须闭合
  • 对于标签首字母:
    • 若以小写字母开头,则将其转换为html中的同名元素,如果html没有该标签对应的同名元素,则报错
    • 若以大写字母开头,react则去渲染对应的组件,若组件没有定义,则报错

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.title{
background-color: orange;
width: 200px;
}
</style>
</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 -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<!-- 注意:这里应该写text/babel,但md不识别语法,为了好看代码用了js-->
<script type="text/javascript">
// JS表达式
const myId = "HoNgYI";
const myData = "Hello, REACT";

// 1.创建虚拟dom
const VDOM = (
<div>
<h2 className="title" id={myId.toLowerCase()}>
<span style={{color: "white", fontSize: "15px"}}>{myData.toLocaleUpperCase()}</span>
</h2>
<h2 className="title" id={myId.toUpperCase()}>
<span style={{color: "white", fontSize: "15px"}}>{myData.toLocaleUpperCase()}</span>
</h2>
<input type="text"/>
</div>
);
// 2.渲染虚拟dom
ReactDOM.render(VDOM, document.getElementById("test"));
</script>
</body>
</html>

执行结果:

image-20220403195340408

2.4.2 练习

需求:动态展示列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</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 -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/javascript">
// 模拟一些数据
const data = ["Angular", "React", "Vue"];

// 1.创建虚拟dom
const VDOM = (
<div>
<h1>前端js框架列表</h1>
<ul>
{
data.map((item, index) => {
return <li key={index}>{item}</li>;
})
}
</ul>
</div>
);
// 2.渲染虚拟dom
ReactDOM.render(VDOM, document.getElementById("test"));
</script>
</body>
</html>

注意:标签内的{}只能写js表达式,不能写js语句。

执行结果

image-20220403202322317

2.5 模块与组件

2.5.1 理解

模块

  • 理解:向外提供特定功能的js程序,一般就是一个js文件
  • 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂
  • 作用:复用js,简化js的编写,提高js运行效率

组件

  • 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)
  • 为什么要用组件: 一个界面的功能更复杂
  • 作用:复用编码,简化项目编码,提高运行效率

2.5.2 模块化和组件化

当应用的js都以模块来编写的, 这个应用就是一个模块化的应用。

当应用是以多组件的方式实现,这个应用就是一个组件化的应用。

3 面向组件编程

3.1 基本理解与使用

组件分为函数式组件和类式组件两种。

3.1.1 React开发者工具

在chrome应用商店中下载:

image-20220403203235962

  • 当项目在开发环境中运行时,开发者工具图标如下显示:

image-20220403203700154

其中:

  1. Components:显示了该页面所包含的组件及其属性
  2. Profiler:记录网页的性能,例如组件加载的时间等等
  • 当项目在生产环境中运行(项目打包并部署在服务器)时,开发者工具图标如下显示:(以美团官网为例)

image-20220403203935662

3.1.2 函数式组件

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</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 -->
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
// 1.创建函数式组件
function MyComponent() {
console.log(this); // undefined,因为babel编译后开启了严格模式use strict
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
// 2.渲染组件到页面
ReactDOM.render(<MyComponent/>, document.getElementById("test"));
</script>
</body>
</html>

执行结果

image-20220416140051848

注意点

  • 根据2.4小节JSX语法规则,组件名称必须以大写字母开头。React 会将以小写字母开头的组件视为原生 DOM 标签。例如,<div/>代表 HTML 的 div 标签,而<Weclome/> 则代表一个组件。此处MyComponent即为大写字母开头的函数式组件。
  • 渲染组件到页面时,写法为<MyComponent>,即为闭合标签的形式
  • 执行了ReactDOM.render(<MyComponent/>, document.getElementById("test"));之后:
    • React解析组件标签,找到了MyComponent组件
    • 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转换为真实DOM,呈现在页面中

3.1.3 类式组件

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id="test"></div>

<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>

<script type="text/babel">
// 1.创建类式组件: 必须继承React.Component
class MyComponent extends React.Component{
// render()函数放在MyComponent的原型对象上,供实例使用
render() {
return <h2>我是用类定义的组件(适用于【复杂组件】的定义</h2>
}
}

// 2.渲染类式组件到页面
ReactDOM.render(<MyComponent/>, document.getElementById("test"));
</script>
</body>
</html>

执行结果

image-20220416142653449

注意点

  • 执行了ReactDOM.render(<MyComponent/>, document.getElementById("test"));之后:

    • React解析组件标签,找到了MyComponent组件

    • 发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render()方法,将返回的虚拟DOM转换为真实DOM,呈现在页面中

3.2 组件实例三大核心属性

3.2.1 state