前端笔记-React-入门

React 简介

React 由 FaceBook 开发,是一个开源的用于构建用户界面的 JavaScript 库。React 还有 React Native 框架,通过它可以直接使用 JS 开发原生应用。

React 的 特点如下:

  • 虚拟 DOM (性能好,操作简单,兼容好)
  • 声明式
  • 基于组件
  • 支持服务器端渲染
  • 快速、简单、易学

React - Hello World

React 是用来代替 DOM 的,那么首先来看传统的 Dom 操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<body>
<div id="root"></div>
<script>
// 通过 dom 添加 div:
// 创建 div
const div = document.createElement('div');
// 向 div 中添加内容
div.innerText = "这是div"
// 获取 root
const root = document.getElementById('root');
// 将 div 添加到 root 下
root.appendChild(div)
</script>
</body>

如使用 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
<head> 
<!-- 引入 react 核心库 和 dom 库 -->
<script src="script/react.development.js"></script>
<script src="script/react-dom.development.js"></script>
</head>
<body>
<div id="react-root"></div>
<script>
// 通过 react 添加 div:
// React.createElement() 方法,用于创建一个 React 元素
// 参数:
// 1. 元素名(组件名)
// 2. 元素中的属性(如:class、id)
// 3. 元素的子元素(内容)
const reactDiv = React.createElement('div', {}, 'react hello world!')

// 获取根元素对应的 React 元素
// ReactDOM.createRoot() 用来创建 React 根元素,需要一个 DOM 元素作为参数
const rooter = ReactDOM.createRoot(document.getElementById("react-root"))

// 将 div 渲染到 root
rooter.render(reactDiv)

</script>
</body>

这里用到了三个方法:React.createElement()ReactDOM.createRoot()root.render(),接下来进行一下详细分析:

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<body>
<button id="btn">我是按钮</button>
<div id="root"></div>
<script>

// React.createElement() 方法
// 参数:
// 1. 元素名(html标签名必须小写,首字母如果大写会被认为是 Root)
// 2. 标签中的属性
// - 设置事件时 - 属性名要用驼峰命名法,内容不要写成字符串代码,写成函数
// - class 属性用 className 来设置
// 3. 元素的子元素(内容),之后的参数也被当做子元素加入
// 注意:
// - createElement 创建的是 React 元素,最终会通过虚拟 DOM 转化为真实 DOM(如果是 React Native,则会转为原生组件)
// - React 元素一旦创建就无法修改(dom 修改操作极其复杂,如果 React 也支持修改,会导致 API 和 dom 一样臃肿)
// - 要修改 React 元素,只能创建新元素替换,这样并不会导致过多性能损失,React会对比新旧对象,只替换更新的部分)
// - 修改 React 元素后,要调用 render 方法重新渲染
const button = React.createElement('button', {
className: 'react-button',
type: 'button',
onClick: ()=>{
alert(1233)
}
}, "按钮");

const div = React.createElement('div', {}, '我是div', button)

// ReactDOM.createRoot() 方法
// 获取根元素
// 根元素是 React 元素要插入的位置
const root = ReactDOM.createRoot(document.getElementById('root'))

// root.render() 方法
// 将 react 元素 div 渲染到根元素中,根元素中所有内容都会被 React 元素替换
// 重复调用 render() 时,React 会确保以最小的修改方式进行渲染,对 DOM 做最小的变化
root.render(div)


// 替换 React 元素示例(并非常规开发过程中使用的,仅作原理展示):
// 获取按钮
const btn = document.getElementById('btn');
// 绑定事件
btn.addEventListener('click', ()=>{
const button = React.createElement('button', {
className: 'react-button',
type: 'button',
onClick: ()=>{
alert('按钮变了')
}
}, "按钮2");

const div = React.createElement('div', {}, '我是div', button)

// 根元素中的所有内容被删除,被 react 元素替换
// 重复调用 render() 时,会使用差分算法(diffing algorithm)比较变化,以最小的变化高效地修改 dom
root.render(div)
})

</script>
</body>

JSX (JavaScript Syntax Extension)

命令式编程:过程导向,告诉编译器,按照什么流程去执行命令:

如果使用上文提到的三个 API,只能以命令式编程的方式进行编程,例如:

1
2
3
// 命令式编程:
// 目的:创建一个 <button>按钮</button>
const btn = React.createElement('button', {}, '按钮')

声明式编程:结果导向,告诉编译器,要什么结果,过程交给框架去实现:

1
2
// 声明式编程
const div = <button>我是按钮</button>

在 React 中,可以通过 JSX ,以类似 HTML 的方式来创建 React 元素,JSX 需要使用 babel 编译为 JS 代码,才能被 React 执行

JSX注意事项

  1. JSX 不是字符串,不加引号

  2. JSX 中 html 标签小写,React 组件大写开头

  3. JSX 中有且仅有一个根标签

  4. JSX 标签必须要正确结束(自结束标签必须写斜杠)

  5. JSX 中可以使用 {} 嵌入表达式(有值的就是表达式)

  6. 如果表达式是空值(布尔、空、undefined) 不会显示、

  7. 在 JSX 中,属性可以直接在标签中设置(class 需要使用 className 设置; style 必须使用对象设置)

渲染列表

在 jsx 中,{} 内只能放表达式,而不能放 if 语句

但可以在 if 语句中操作 jsx

1
2
3
4
5
6
7
8
9
10
11
12
13
const name = 'Takuzen'
const lang = 'en'

let div;

if (lang == 'en'){
div = <div> hello {name} </div>
} else if (lang == 'cn'){
div = <div> 你好 {name} </div>
}

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(div)

如果要将 array 在网页中渲染,不需要使用循环,jsx会自动将数组进行遍历,然后渲染

1
2
3
const array = ['孙悟空', '猪八戒', '沙和尚']

const list = <div> {array} </div>

如果要将 array 在网页中渲染为列表,可以将数组中的元素都包上 <li></li>

1
2
3
4
5
6
7
8
9
10
11
12
13
const data = ['孙悟空', '猪八戒', '沙和尚']
const array = []

// 遍历 data,变为列表
for (let i = 0; i < data.length; i++) {
array.push(<li>{data[i]}</li>)
}

// 或使用 map
const list = <ul> {array} </ul>

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(list)

对数组遍历生成新数组的过程也可以使用 map() 方法实现:

1
2
3
4
5
6
7
8
9
const data = ['孙悟空', '猪八戒', '沙和尚']

// 使用 map 遍历
// map 方法返回的是值,在jsx中使用要加 {}
// item 是参数,在jsx中使用要加 {}
const list = <ul> {data.map(item => <li>{item}</li>)} </ul>

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(list)

虚拟 DOM

在 React 中操作的是 React元素,而非 原生DOM 元素

React 通过 虚拟DOMReact元素原生DOM进行映射,虽然操作的是 React元素,但这些操作最终会在 原生DOM 上 体现

虚拟DOM 有以下好处

  1. 降低 API 复杂度

  2. 解决兼容问题

  3. 提升性能(减少不必要的 DOM 操作)

每当调用 root.render() 时,页面重新渲染:

  1. React 会通过 diffing 算法,将新的元素和旧的元素进行比较(自上而下逐层对比新旧元素,如果上层就不一样,直接修改,一样再继续往下层比较)
  2. 通过比较,React 找到发生变化的元素,并且只对变化的元素进行修改,没有变化的不予处理

在 JSX 中显示数组,数组中每个元素都要设置一个唯一的 key,否则会显示警告,这是因为:

重新渲染页面时,React 会按照顺序依次比较元素,如果不指定 key,也按照顺序比较;

如果数组元素顺序没有变化,则没有影响,但如果列表顺序变化了,可能会导致性能问题(在最后添加没有影响,在开头添加可能导致全部重新渲染);

开发时一般使用 id 作为 key,有些场景可以使用 index 作为 key(性能较差,和没用index 一样,只能消除警告)


前端笔记-React-入门
https://username.github.io/2022/11/08/前端笔记-React-入门/
作者
ZhuoRan-Takuzen
发布于
2022年11月8日
许可协议