1 相关术语

  • React: 用于构建用户界面的 JavaScript 库
  • node: 通过 JavaScript 语言开发 web 服务端
  • npm:相当于 python 的 pip 工具,pip 用于安装 python 相关的各种工具,npm 用于 Node.JS 相关的各种工具
  • jsx:JSX 是一种 JavaScript 的语法扩展,用于 react 中,既不是字符串也不是 HTML,有点像模板,形如:
1
<div>{arr}</div>

2 react 与只有 JS 的区别

单纯的 JS 是直接操作和构造 html。

react 是数据驱动界面,它通过虚拟的 html 生成标签。

react 的基础逻辑是数据由上向下单向流动。

虚拟的 html 有点类似于模板,html 中其中可嵌入变量和程序段。

举个例子,之前提交表单时将表单中每个元素取值转给 server,也就是从 html 中取值;使用 react 后,当按下按钮时,一般调用某个 react 函数,由函数内部通过数据构造请求,以及处理请求的结果,再进一步渲染控件,而非整个刷新整个界面。

3 基本概念

3.1 组件

组件 component 是 react 的核心概念,一般功能都通过组件实现。

组件名首字符必须大写,否则被认为是标签。

react 中有两种组件:函数组件(Functional Components) 和类组件(Class Components)。

3.1.1 函数组件

1
2
3
4
5
6
7
8
9
10
11
12
import React from 'react';
import ReactDOM from 'react-dom';

function MyFuncComp() {
return <h1>组件内容</h1>
}
ReactDOM.render(
<div>
<MyFuncComp/>
</div>,
document.getElementById("root")
);

3.1.2 类组件

继承自 Component,且至少实现 render 函数;constructor 为其构造函数,参数 props 用于接收外部传来的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
import React, { Component } from 'react'
export default class MyClassComp extends Component {
constructor(props) {
super(props)
console.log(props)
this.state = {
initData: this.props.time
}
}
render() {
return <h1>组件内容</h1>
}
}

3.1.3 组件状态

组件可以维护自己的数据,可将状态看作组件的属性。

具体实现,如上例中的 this.state={xxx}。

不能直接改变 state,否则无法引发界面刷新,需要使用 setState 函数:

1
2
3
this.setState({
initData: this.state.initData - 1
});

3.1.4 Bind 函数

ES5 之前,函数自动 bind,而在 ES6 之后,需要手动 bind 函数,比如:回调函数需要在构造里 bind,形如:

1
2
3
4
5
6
7
render() {
return (
<input type="button" value="Log" onClick={this.logMessage.bind(this)} />
);
}
//或者用箭头方式bind
//<input type="button" value="Log" onClick={() => this.logMessage()} />

3.1.5 控件的 Key

key 可以帮助 React 高效识别哪些元素发生了改变,哪些元素没有发生改变。最好给每个控件指定 key,比如:

1
2
3
4
5
6
7
8
9
render () {
return (
<ul>
{this.state.todoItems.map(({task, uid}) => {
return <li key={uid}>{task}</li>
})}
</ul>
)
}

这使得每个控件得以区分,控制刷新,提升效率……

3.1.6 组件之间通讯

react 主导思想是数据只能从父控件向子控件流动,兄弟组件间不能通讯;数据只能被组件内部及其子组件使用。父子组间通讯,常使用方法。

  • 通过设置属性 props 把父组件数据传给子组件
  • 通过设置属性 props 把父组件句柄传给子组件,使子组件可调父组件中的方法(使用时注意 bind)

4 生命周期

详见 详解React生命周期(包括react16最新版)

5 第一个程序

5.1 新建一个项目

1
2
$ create-react-app frontend
$ cd frontend

5.2 写代码

5.2.1 react 简单示例

删除 src/下所有文件,并编辑 src/index.js 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component {
render() {
return (
<div className="container">
<h1 className="center-align">
盒装一流弊<br/>
<span className="waves-effect waves-light btn">
<i className="material-icons right">cloud</i>您说的都对
</span>
</h1>
</div>
);
}
}

ReactDOM.render(<App />, document.getElementById('root'))

5.2.2 react-bootstrap 示例

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
import React from 'react';
import ReactDOM from 'react-dom'
import {Button,Form} from 'react-bootstrap'

class FormInstance extends React.Component {
render() {
return(
<html>

<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email" />
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>

<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password" />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicCheckbox">
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>

</html>
)
}
};

ReactDOM.render(<FormInstance />, document.getElementById('root'))

5.3 在浏览器中运行

启动浏览器看运行效果

1
$ sudo npm start

5.4 编译

1
$ npm run build

此时 build 目录下生成 index.html 及 static/js/,把它们复制到你的 flask 项目里,调用 index.html 即可看到用 react 生成的网页。

6 使用 VSCode 调试 React 应用

  • 安装 Debugger for Chrome 插件
  • 从 vscode 左侧调出运行与调式面板
  • 设置配置 launch.js,将端口改为 3000
  • 在终端输入 npm start,即可运行调试
  • 此时在浏览器中可看到界面,修改界面不需要再次运行,即可在浏览器中同步看到效果

7 react+bootstrap

1
$ sudo npm install react-bootstrap bootstrap@3.3.7

安装好后,就可以在 react 中直接使用了,如:

1
import { Navbar, Jumbotron, Button } from 'react-bootstrap';

8 简单范例

1
2
3
4
$ git clone https://github.com/lingjiawen/react_bootstrap_demo.git
$ cd react_bootstrap_demo
$ npm install
$ npm run dev

此时,可以在浏览器打开 localhost:8080,看到示例

9 编译前端代码

9.1.1 为什么编译

即使用 babel 这样的库可以在运行时编译 html,但会遇到以下问题:

  • 在 js 中引入文件,如“import xxx from yyy”时,如果 yyy 是编译过的 xxx 可能找不到。
  • yyy 往往是多个 js 文件的集合,无法单独使用
  • 自己的 js 中可能使用了多个库,都放进项目里占空间大且乱

9.1.2 如何编译

1
$ npm run build

编译后在 build 目录下生成 html 和 js 文件

10 问题与解决

10.1 问题一

  • 问题:npm start 时报错:code: 'MODULE_NOT_FOUND'
  • 分析:这是由于 npm 和 node 版本不一致引起的
  • 解决方法:升级 npm
1
2
$ sudo n 6.3 # 降级node版本
$ sudo npm install npm -g # 升级npm版本

10.2 问题二

  • 问题:npm 升级了多个软件包后由于版本不匹配而无法工作
  • 分析:冲突异致,由于 npm 安装了很多软件,导致使用 apt remove 删除 npm 后,冲突依然存在;当 npm 不能正常运行时,也无法管理被它安装的软件包。
  • 解决方法:删除 npm 以及所有的缓存和相关安装包,它们的位置如下:
1
2
3
4
HOME/.npm/*
/usr/local/lib/node_modules/
/usr/local/bin/npm
/usr/local/bin/node

10.3 问题三

  • 问题:console.log() 在哪显示
  • 解决:在浏览器 F12,控制台里显示

10.4 问题四

  • 问题:访问本机提供服务的端口时报错:No 'Access-Control-Allow-Origin' 跨域问题
  • 分析:跨域问题
  • 解决方法:在 flask 里设置一下 CORS,形如:
1
2
3
from flask_cors import CORS
app = Flask(__name__)
CORS(app)

10.5 问题五

  • 问题:什么是脚手架
  • 回答:一个工作,用于快速地构建开发环境

10.6 问题六

  • 问题:如何一次渲染多个组件
  • 回答:
1
2
3
4
5
6
7
render() {
<div>
<MyComponent1 />
<MyComponent2 />
<MyComponent3 />
</div>
}

10.7 问题七

  • 问题:如何调试 JSX
  • 回答:JSX 中可通过{}加入简单代码段

10.8 问题八

  • 问题:用 create-react-app 创建的项目太大,无法保存
  • 回答:去掉 node-modules 目录,只保存其它即可

10.9 问题九

  • 问题: js 文件不能立即更新
  • 回答: 浏览器 ->F12->网络面板 ->停用缓存

10.10 问题十

问题:不编译是否可以使用 react

回答:在网站中加入少量 react 代码时,可使用 bebel 工具,直接在 js 中使用 jsx 语法,引入以下包:

1
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

详见:在网站中添加 React

10.11 问题十一

问题:如何实现同时使用 jsx 和 import

回答:script type 只能设置一个值,用以下方法同时作为 module 和 bebal

1
<script data-plugins="transform-es2015-modules-umd" type="text/babel">

11 参考

使用 VSCode 调试 React 应用

React Bootstrap官网

React 简单介绍

React Bootstrap Get Start

详解React组件生命周期

12 发现

它可以用不同的 class 描绘不同的控件

setstate 会触发渲染

控制台会打出错误信息

13 访问远程数据

1
$ npm isntall axios --save

14 复杂示例

react 利用select编写省市级三级联动