Web学习笔记-React(配置环境、ES6语法补充、Components)

  1. 1. React配置环境
  2. 2. ES6语法补充
  3. 3. Components

本文记录 React 的学习过程,内容为配置环境、ES6 语法补充、Components。
React 是一个用于构建用户界面的库。React 不是一个框架,它的应用甚至不局限于 Web 开发,它可以与其他库一起使用以渲染到特定环境。
React 官网:React

1. React配置环境

React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作 components。React 能够构建那些数据会随时间改变的大型应用。

React 特性:

  • React 为了能够方便地去维护我们的页面,它在内存里面创建了一个虚拟的 DOM 树:Virtual DOM,这是一个轻量级的虚拟的 DOM,就是 React 抽象出来的一个对象,描述 DOM 应该什么样子的,应该如何呈现。通过这个 Virtual DOM 去更新真实的 DOM,由这个 Virtual DOM 管理真实 DOM 的更新。
  • 数据驱动:当某一个元素里的数据发生变化后,React 会重新将有可能修改的元素都修改一遍,然后与真实的 DOM 树对比是否有区别,React 分析完后最终只会修改真实改变的结点。由于在内存里修改对象的速度很快,因此 React 效率很高。
  • React 一般不直接手写 JS,而是通过编写 JSX 文件,JSX 比 JS 更好写一点,React 会先将 JSX 编译成 JS。

(1)安装 Git BashWindows 安装配置 Git 教程

(2)安装 NodeJSNodeJS 的安装及配置

(3)安装 create-react-app

打开 Git bash,执行以下命令:

1
npm i -g create-react-app

如果速度很慢,可以先修改镜像源再尝试安装:

1
2
npm config set registry https://registry.npm.taobao.org
npm i -g create-react-app

如果安装完成后出现警告:npm WARN deprecated tar@2.2.2: This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.,可以先更新 tar 试试:

1
npm install -g tar

如果还是有警告,且创建项目时(例如执行 create-react-app react-app)报错:bash: create-react-app: command not found,使用 npx 创建项目:

1
npx create-react-app my-app

或者用 npm 创建项目:

1
npm init react-app my-app

创建好后进入项目文件夹启动项目:

1
2
cd my-app
npm start

启动后访问 localhost:3000 即可访问页面,ctrl+c 可停止服务。

(4)配置 VS Code 插件:Simple React Snippets、Prettier - Code formatter

Simple React Snippets 为 React 智能化自动补全插件。

例如输入 imrc 即可补全出以下内容:

1
import React, { Component } from 'react';

输入 cc 即可补全出以下内容:

1
2
3
4
5
6
7
8
class Example extends Component {
state = { }
render() {
return ();
}
}

export default Example;

Prettier - Code formatter 为代码格式化插件,安装好后在 JSX 代码中通过 VS Code 一键格式化快捷键:ctrl + k + f 即可配置格式化插件。

(5)创建 React App

在目标目录下右键打开 Git Bash,在终端中执行:

1
2
3
npx create-react-app react-app  # react-app是新建项目的名字,可以替换为其他名称
cd react-app
npm start # 启动应用

启动成功后会在本地开一个3000端口,页面效果已在上文展示。此时使用 VS Code 打开 react-app 文件夹可以看到项目的目录结构。

其中,node_modules 用来维护各种 JS 库,未来安装的所有依赖项都会放在该文件夹下;public 中的 index.html 就是我们未来渲染出的页面,该文件中只有一个 <div id="root"></div>src 中的 index.js 代码如下:

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root')); // 获取div同时创建为一个React对象
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);

其中 App 的定义在 App.js 中:

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
import logo from './logo.svg';
import './App.css';

function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}

export default App;

App 组件就定义了页面的具体内容,且我们能够发现该 JS 文件中有 HTML 代码,因此该文件即为 JSX 文件,能够在 JavaScript 的基础上支持 XML(可扩展标记语言),HTML 也是一种特殊的 XML。

JSX 是 React 中的一种语言,会被 Babel 编译成标准的 JavaScript。

2. ES6语法补充

ES6,全称 ECMAScript 6.0,是 JavaScript 的版本标准。此处添加一些 React 中常用的语法糖。

(1)使用 bind() 函数绑定 this 取值

在 JavaScript 中,函数里的 this 指向的是执行时的调用者,而非定义时所在的对象。例如:

1
2
3
4
5
6
7
8
9
10
11
const person = {
name: "abc",
talk: function() {
console.log(this);
}
}

person.talk();

const talk = person.talk;
talk();

运行结果为:

1
2
{name: 'abc', talk: f}
undefined

使用 bind() 函数绑定 this 的取值为 person。例如:

1
const talk = person.talk.bind(person);

运行结果为:

1
2
{name: 'abc', talk: f}
{name: 'abc', talk: f}

(2)箭头函数的简写方式

当函数参数只有一个时可以将括号去掉,当函数体只有一个 return 语句时可以把 return{} 一起去掉,例如:

1
2
3
const f = (x) => {
return x * x;
};

等价于:

1
const f = x => x * x;

(3)箭头函数不重新绑定 this 的取值

1
2
3
4
5
6
7
8
9
const person = {
talk: function() {
setTimeout(function() {
console.log(this);
}, 1000);
}
};

person.talk(); // 输出Window
1
2
3
4
5
6
7
8
9
const person = {
talk: function() {
setTimeout(() => {
console.log(this);
}, 1000);
}
};

person.talk(); // 输出 {talk: f}

(4)对象的解构

1
2
3
4
5
6
7
const person = {
name: "abc",
age: 18,
height: 180,
};

const {name : new_name, age} = person; // new_name是name的别名

(5)数组和对象的展开

1
2
3
4
5
6
7
let a = [1, 2, 3];
let b = [...a]; // b是a的复制,和a不是一个数组,如果写let b = a则b和a是同一个数组
let c = [...a, 4, 5, 6]; // c = [1, 2, 3, 4, 5, 6]

let d = {name: "abc"};
let e = {age: 18, height: 180};
let f = {...d, ...e, weight: 120}; // f = {name: "abc", age: 18, height: 180, weight: 120}

(6)Named exports 与 Default exports

  • Named Export:可以 export 多个,import 的时候需要加大括号,名称需要匹配,即之前使用的方式。
  • Default Export:最多 export 一个,import 的时候不需要加大括号,可以直接定义别名。

3. Components

React 应用程序是由组件(Component)组成的。组件是一段可重用代码,一个组件是 UI(用户界面)的一部分,它拥有自己的逻辑和外观,用于渲染、管理和更新应用中的 UI 元素。组件可以小到一个按钮,也可以大到整个页面。

(1)创建项目

首先创建一个新项目 box-app

1
2
3
npx create-react-app box-app
cd box-app
npm start

安装 bootstrap 库:

1
npm i bootstrap

bootstrap 的引入方式:

1
import 'bootstrap/dist/css/bootstrap.css';

(2)创建 Component

src 文件夹中创建一个文件夹 components 存放组件,然后在 components 文件夹中创建一个 JSX 文件 box.jsx(使用 .js 后缀也一样,只是用 .jsx 后区分起来跟明显一点)其框架如下:

1
2
3
4
5
6
7
8
9
10
import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component { // 输入cc即可补全
state = { }
render() { // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
return (<h1>Hello World!</h1>);
}
}

export default Box;

然后我们需要在 index.js 中将组件渲染出来:

1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import 'bootstrap/dist/css/bootstrap.css';
import Box from './components/box';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Box />
</React.StrictMode>
);

(3)创建按钮

由于 Component 中的 render() 函数只能 return 一个元素,因此当子节点数量大于1时,可以用 <div><React.Fragment> 将其括起来。

(4)内嵌表达式

JSX 中使用 {} 在 HTML 标签中嵌入表达式。

(5)设置属性

由于 class 是 JS 中的关键字,因此 HTML 标签中的 class 需要改为 className。CSS 属性也需要修改,例如:background-color 修改为 backgroundColor,其它属性也是类似的。

以上的综合示例:

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
import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component { // 输入cc即可补全
state = {
x: 0
};

styles = {
width: '50px',
height: '50px',
backgroundColor: 'lightblue',
color: 'white',
textAlign: 'center',
lineHeight: '50px',
borderRadius: '5px'
};

render() { // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
return (
// HTML标签中可以使用{}写一个表达式
<React.Fragment>
<div style={this.styles}>{this.state.x}</div>
<button className='btn btn-primary m-2'>Left</button>
<button className='btn btn-success m-2'>Right</button>
</React.Fragment>
);
}
}

export default Box;

(6)数据驱动改变 Style

例如:

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
import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component { // 输入cc即可补全
state = {
x: 1
};

render() { // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
return (
// HTML标签中可以使用{}写一个表达式
<React.Fragment>
<div style={this.getStyles()}>{this.state.x}</div>
<button className='btn btn-primary m-2'>Left</button>
<button className='btn btn-success m-2'>Right</button>
</React.Fragment>
);
}

getStyles() {
let styles = {
width: '50px',
height: '50px',
backgroundColor: 'lightblue',
color: 'white',
textAlign: 'center',
lineHeight: '50px',
borderRadius: '5px'
};

if (this.state.x === 0) {
styles.backgroundColor = 'orange';
}

return styles;
}
}

export default Box;

(7)渲染列表

可以使用 map 函数渲染一个列表,每个元素需要具有唯一的 key 属性,用来帮助 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
import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component { // 输入cc即可补全
state = {
x: 1,
colors: ['red', 'green', 'blue']
};

render() { // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
return (
// HTML标签中可以使用{}写一个表达式
<React.Fragment>
<div>{this.state.x}</div>
<button className='btn btn-primary m-2'>Left</button>
<button className='btn btn-success m-2'>Right</button>
{this.state.colors.map(color => (
<div key={color}>{color}</div>
))}
</React.Fragment>
);
}
}

export default Box;

(8)Conditional Rendering

利用逻辑表达式的短路原则:

  • 与表达式中 expr1 && expr2,当 expr1 为假时返回 expr1 的值,否则返回 expr2 的值。
  • 或表达式中 expr1 || expr2,当 expr1 为真时返回 expr1 的值,否则返回 expr2 的值。

(9)绑定事件

例如可以使用 onClick 绑定按钮的点击事件,注意需要妥善处理好绑定事件函数的 this,示例如下:

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
import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component { // 输入cc即可补全
state = {
x: 1
};

handleClickLeft() { // 如果不用箭头函数或者下面调用函数时使用bind(this)的话this会变成undefined
console.log('click left', this);
}

handleClickRight = () => {
console.log('click right', this);
}

render() { // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
return (
// HTML标签中可以使用{}写一个表达式
<React.Fragment>
<div>{this.state.x}</div>
<button onClick={this.handleClickLeft} className='btn btn-primary m-2'>Left</button>
<button onClick={this.handleClickRight} className='btn btn-success m-2'>Right</button>
</React.Fragment>
);
}
}

export default Box;

(10)修改 state

需要使用 this.setState() 函数,每次调用 this.setState() 函数后,会自动重新调用 this.render() 函数,用来修改虚拟 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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component { // 输入cc即可补全
state = {
x: 1
};

handleClickLeft = () => {
// this.state.x--; 这样写的话React不会修改前端页面的效果
this.setState({
x: this.state.x - 1
});
}

handleClickRight = () => {
this.setState({
x: this.state.x + 1
});
}

render() { // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
return (
// HTML标签中可以使用{}写一个表达式
<React.Fragment>
<div style={this.getStyles()}>{this.state.x}</div>
<button onClick={this.handleClickLeft} className='btn btn-primary m-2'>Left</button>
<button onClick={this.handleClickRight} className='btn btn-success m-2'>Right</button>
</React.Fragment>
);
}

getStyles() {
let styles = {
width: '50px',
height: '50px',
backgroundColor: 'lightblue',
color: 'white',
textAlign: 'center',
lineHeight: '50px',
borderRadius: '5px',
position: 'relative',
left: this.state.x
};

if (this.state.x === 0) {
styles.backgroundColor = 'orange';
}

return styles;
}
}

export default Box;

(11)给事件函数添加参数

可以定义一个临时函数绑定事件,然后在该函数中调用原函数并传入参数,或者直接在绑定事件的时候用一个临时的箭头函数返回传入参数的原函数。例如:

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
import React, { Component } from 'react';  // 输入imrc即可补全

class Box extends Component { // 输入cc即可补全
state = {
x: 1
};

handleClickLeft = (step) => {
this.setState({
x: this.state.x - step
});
}

handleClickRight = (step) => {
this.setState({
x: this.state.x + step
});
}

handleClickLeftTmp = () => {
this.handleClickLeft(10);
}

render() { // Component类的函数,用来返回当前组件最后渲染的HTML结构是什么
return (
// HTML标签中可以使用{}写一个表达式
<React.Fragment>
<div style={this.getStyles()}>{this.state.x}</div>
<button onClick={this.handleClickLeftTmp} className='btn btn-primary m-2'>Left</button>
<button onClick={() => this.handleClickRight(10)} className='btn btn-success m-2'>Right</button>
</React.Fragment>
);
}

getStyles() {
let styles = {
width: '50px',
height: '50px',
backgroundColor: 'lightblue',
color: 'white',
textAlign: 'center',
lineHeight: '50px',
borderRadius: '5px',
position: 'relative',
left: this.state.x
};

if (this.state.x === 0) {
styles.backgroundColor = 'orange';
}

return styles;
}
}

export default Box;

上一章:Web学习笔记-JavaScript

下一章:Web学习笔记-React(组合Components)