React学习

React学习

最近课好少啊,芜湖起飞~

主要的参考资料:

1.React元素渲染

1.1 从官方模板开始

值得注意的是,react启动之后,直接修改代码然后ctrl+s,页面会重新reload,非常的人性化~

我们从零开始,在刚新建好react项目的中可以看到./public/index.html页面可以看到有个<div id="root"></div>的节点,我们的react组件其实都是渲染在这个里面的。

我们看到./src/index.js,其实就是将一个<App />对象渲染到root节点上,这个<App />对象是在./src/App.js中定义的,通过import导入进来的。

1
2
3
4
5
6
7
8
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// 使用ReactDOM.render方法渲染,将<App />渲染到root节点上
ReactDOM.render(<App />,document.getElementById('root'));
serviceWorker.unregister();

wW4Du4.png

可能会对<App />的样子所迷惑,其实就是一个对象,我们换种方式写可能会更加清楚(下面代码的效果同上)

1
2
3
4
5
6
7
8
9
10
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// <App />就是我们的一个组件对象
let app = <App />;
let root = document.getElementById('root');
ReactDOM.render(app ,root);
serviceWorker.unregister();

这样就非常明了,ReactDOM.render()方法其实就是接收两个参数,将组件对象渲染到一个DOM节点上。

1.2 尝试自己编写对象

我们大概知道渲染的工作流程,我们就可以编写自己的对象,然后渲染到节点。这个代码非常简单,直接看~

1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// 定义一个对象,比如这里的一个h1标签,这里没有用"括起来,这是JSX的写法
// JSX是JS的语法扩展,运用于React中
// 值得注意的是这个对象只能有一个根结点
let h1 = <h1>hello world</h1>;
let root = document.getElementById('root');
ReactDOM.render(h1, root);

wWTlin.png

不过有一点值得注意,这样的JS对象只能有一个根结点,也就是说下面这种写法是不允许的!

1
let h1 = <h1>hello world</h1><h2>yeah</h2>;

所以如果有需要我们一般使用<div>标签括起来:

1
let h1 = <div><h1>hello world</h1><h2>yeah</h2></div>;

wWTvYn.png

有时候可能对象比较冗长,为了美观,我们用括号括起来,采用下面这种写法:

1
2
3
4
5
6
let h1 = (
<div>
<h1>hello world</h1>
<h2>yeah</h2>
</div>
);

1.3 写点高级的对象

成天hello world也太枯燥了叭,我们来实现一个时钟吧!

其实也非常的简单,我们只需要使用JS标准对象Date获取之间,然后显示即可,当然为了让时钟能够实时更新,所以我们需要使用到间隔函数setInterval()

上代码:

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';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// way1
function clock(){
let time = new Date().toTimeString();
// JSX传入参数和JS语法也有一些小区别
let element = (
<div>
<h1>现在时间是:{time}</h1>
</div>
)
let root = document.getElementById('root');
ReactDOM.render(element, root);
}

setInterval(clock, 1000); // 间隔函数,实现页面刷新, 1000ms刷新一次

wfCxhV.png

1.4 函数式组件

上面的时钟还有另外一种实现的方式,就是使用函数式组件,就类似于刚开始官方模板中的App那样的对象

值得注意的是,函数式组件首字母要大写,然后就能顺利的使用函数式组件了,使用格式<name para = {}/>,注意不要漏掉了后面的/符号

上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// way2
// 函数式组件,注意函数式组件命名首字母要大写!!
function Clock(para){ // para为传入参数
return (
<div>
<h1>现在时间是:{para.date.toLocaleTimeString()}</h1>
</div>
)
}
// 使用函数式组件 <name para = {}/>
function run(){
ReactDOM.render(
<Clock date = {new Date()}/>,
document.getElementById('root')
)
}
// run()
setInterval(run, 1000);
serviceWorker.unregister();

时钟效果和上文1.3相同

2.JSX

React使用JSX替代常规的Javascript,类似于XML的Javascript扩展,相较于JS他有许多是好处

  • JSX执行更快,在编译成JavaScript代码后进行了优化
  • 更加安全,以为其将变量放在{}中,在渲染时会过滤传入的值,确保不会遭受注入攻击
  • 编写模板也十分简单快速(没vue快吧^_^)

但是也有一些值得注意的地方

  • JSX必须要有根节点
  • 正常的HTML元素要小写,大写会被认为是组件

2.1 jsx表达式{}

2.1.1 放变量

这个比较简单,前面我们也有使用过

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
let name = 'panfeng' // 放入变量
let h1 = (
<div>
<h1>hello {name}</h1>
</div>
);
let root = document.getElementById('root');
ReactDOM.render(h1, root);
serviceWorker.unregister();

wfmHPJ.png

2.1.2 放表达式

注意只能放入一个表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
let h1 = (
<div>
<h1>1+1={1+1}</h1>
</div>
);
let root = document.getElementById('root');
ReactDOM.render(h1, root);
serviceWorker.unregister();

wfn3Mq.png

2.1.3 放HTML标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
// 放入标签
let h1 = (
<div>
<h1>你你你你要跳舞吗?</h1>
<h1>{<button>yes</button>}</h1>
</div>
);
let root = document.getElementById('root');
ReactDOM.render(h1, root);
serviceWorker.unregister();

2.1.4 放入CSS样式

新建一个css文件:

1
2
3
4
5
6
.beRed{
background-color: red;
}
.h{
height: 200px;
}

然后在JS文件中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
import App from './App';
import * as serviceWorker from './serviceWorker';
// 放入css样式
let h1 = (
<div className = {'beRed h'}>
<h1>你你你你要跳舞吗?</h1>
</div>
);
let root = document.getElementById('root');
ReactDOM.render(h1, root);
let root = document.getElementById('root');
ReactDOM.render(h1, root);
serviceWorker.unregister();

这样就加入了样式

wf3Uns.png

但是只能注意的是尽量使用className,因为class也是JS的一个关键字

2.1.5 注释

在对象中注释也是需要用{}

1
2
3
4
5
6
7
8
let h1 = (
<div className = {'beRed'}>
{/*我是注释 */}
<h1>你你你你要跳舞吗?</h1>
<img alt = 'baidu' src = 'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'></img>
<h1>{<button>yes</button>}</h1>
</div>
);

3.React样式

除了使用css样式,我们也可以使用React的样式,但是React样式必须使用驼峰法,比如borderBottom,和css不一致,用起来很不方便T_T,算了吧,还是用css吧~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
import App from './App';
import * as serviceWorker from './serviceWorker';
// 使用react样式
let styleExample1 = {
background:"blue",
borderBottom:"4px solid red"
}
let h1 = (
<div style = {styleExample1}>
<h1>你你你你要跳舞吗?</h1>
</div>
);
let root = document.getElementById('root');
ReactDOM.render(h1, root);
serviceWorker.unregister();

4.React组件

4.1 函数式组件

这个我们前面已经使用过了, 函数式组件又被称为静态组件,因为其没有状态或者生命周期可言

我们来看一个嵌套的函数式组件

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
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
//import App from './App';
import * as serviceWorker from './serviceWorker';
// 函数式组件
// 第一个组件
function Dance(para){
return(
<h1>Do you want dance {para.name} ?</h1>
)
}
// 第一个组件放入第二个组件
function Hello(para){
return(
<div>
<h1>Hello {para.name}</h1>
<Dance name = {para.name}/>
</div>
)
}
function run(){
let root = document.getElementById('root');
ReactDOM.render(<Hello name = {'panfeng'}/>, root);
}
run();
serviceWorker.unregister();

4.2 类组件

4.2.1 类组件传参

类组件又被称为动态组件,这里我感觉学的还是比较浅,之后再加一些高级的功能吧~这里只是简单的用了一下类组件

值得注意的是,传参后,类组件内使用this.props获取参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
//import App from './App';
import * as serviceWorker from './serviceWorker';
// 类组件定义
class Hello extends React.Component{
render(){
return(
<div>
<h1>hello world {this.props.name}</h1>
</div>
)
}
}
ReactDOM.render(<Hello name = {'panfeng'}/>, document.getElementById('root'));
serviceWorker.unregister();

4.2.2 类组件状态

温馨提示:想直接看正确操作请跳到最后

样例1 时钟

类组件的状态就类的属性,比如我们仍然希望实现一个时钟页面,我们就能用一个属性来存储时间,然后我们可能就会写出如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
//import App from './App';
class Clock extends React.Component{
constructor(props){
super(props)
this.state = { // 类组件state
time:new Date().toLocaleTimeString()
}
}
render(){
return(
<div>
<h1>当前时间:{this.state.time}</h1>
</div>
)
}
}
ReactDOM.render(<Clock />, document.getElementById('root'))

然而我们会发现我们的时钟并不会动,这也能够理解,因为只渲染了一次嘛,于是我们心中萌生了一个想法,使用setInterval()多次渲染就可以了,恰巧React类中有一个生命周期函数componentDidMount(),会再类组件完成渲染后调用,于是我们又会写出如下的代码:

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
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
//import App from './App';
class Clock extends React.Component{
constructor(props){
super(props)
this.state = { // 类组件state
time:new Date().toLocaleTimeString()
}
}
render(){
return(
<div>
<h1>当前时间:{this.state.time}</h1>
</div>
)
}

// 生命周期函数,再组件完成渲染时调用的函数
componentDidMount(){
setInterval(()=>{
ReactDOM.render(<Clock />, document.getElementById('root'));
},1000)
}
}
ReactDOM.render(<Clock />, document.getElementById('root'))

很不巧的是,我们会发现时钟还是没有动起来,这时候我们才醒悟过来,类的属性值可能一直都没有修改,于是我们又会写出如下的代码:

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 from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
//import App from './App';
class Clock extends React.Component{
constructor(props){
super(props)
this.state = { // 类组件state
time:new Date().toLocaleTimeString()
}
}
render(){
return(
<div>
<h1>当前时间:{this.state.time}</h1>
</div>
)
}

// 生命周期函数,再组件完成渲染时调用的函数
componentDidMount(){
setInterval(()=>{
this.state.time = new Date().toLocaleTimeString(); // 更新时间
ReactDOM.render(<Clock />, document.getElementById('root'));
},1000)
}
}
ReactDOM.render(<Clock />, document.getElementById('root'))

但是此时系统又温馨的提示我们不要直接修改state,而使用setState()函数

wfaak9.png

于是我们终于修改好了,并且发现此时甚至不需要我们手动重新渲染整个页面了,妙啊~

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
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
//import App from './App';
class Clock extends React.Component{
constructor(props){
super(props)
this.state = { // 类组件state
time:new Date().toLocaleTimeString()
}
}
render(){
return(
<div>
<h1>当前时间:{this.state.time}</h1>
</div>
)
}

// 生命周期函数,再组件完成渲染时调用的函数
componentDidMount(){
setInterval(()=>{
this.setState({
time:new Date().toLocaleTimeString() // 更新时间
})
},1000)
}
}
ReactDOM.render(<Clock />, document.getElementById('root'))

并且我们使用setState()时其并不是立马修改DOM中的内容,而是修改虚拟DOM,等setState()执行完后,再对比虚拟DOM和DOM中的内容,再做统一修改,提高效率(不知比之前重新渲染页面效率要高多少~)

样例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
40
41
42
43
44
45
46
47
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css'; // 引入样式文件
//import App from './App';
class Clock extends React.Component{
constructor(props){
super(props)
this.state = { // 类组件state
c1:'visible',
c2:'unvisible'
}
this.clickEvent = this.clickEvent.bind(this) // 需要绑定一下!!
}

clickEvent(e){
console.log(e.target.dataset.index)
let index = e.target.dataset.index; // 获取点击
if(index == '1'){ // 判断是哪个按钮点击
this.setState({
c1:'visible',
c2:'unvisible'
})
}
else{
this.setState({
c1:'unvisible',
c2:'visible'
})
}
}
render(){
return(
<div>{/*绑定按钮事件*/}
<button data-index = '1' onClick = {this.clickEvent}>按钮1</button>
<button data-index = '2' onClick = {this.clickEvent}>按钮2</button>
{/*在此处使用状态*/}
<div className = {this.state.c1}>
<h1>内容1</h1>
</div>
<div className = {this.state.c2}>
<h1>内容2</h1>
</div>
</div>
)
}
}
ReactDOM.render(<Clock />, document.getElementById('root'))

4.2.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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css';
// 创建父元素
class ParentCom extends React.Component{
constructor(props){
super(props);
this.state = {
isActive:true // 控制子元素的状态
}
this.clickFunc = this.clickFunc.bind(this); // 绑定
}
clickFunc(){
this.setState({
isActive: ! this.state.isActive // 点击函数,每次点击就对子元素的状态求反
})
}
render(){
return (
<div>
<button onClick = {this.clickFunc}>控制子元素显示</button>{/*控制子元素的按钮*/}
<ChildCom isActive = {this.state.isActive}/>{/*添加子元素*/}
</div>
)
}
}
// 子元素
class ChildCom extends React.Component{
constructor(props){
super(props);
}
render(){
// 获取参数
let classType = (this.props.isActive == true ? ' active':'');
return (
<div className = {'content'+classType}>{/*使用参数*/}
<h1>我是子元素</h1>
</div>
)
}
}

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

实现效果,按钮控制元素显示

wIPs81.png

4.2.4 类组件子传父

有时候我们也有需要修改父元素的需要,但是通过参数传入父元素的this.state的值并不能完成修改,但是我们还要其他的方式,可以通过参数传入父元素的函数,然后子元素调用这个父元素的函数就能完成对父元素的修改了,其实思路也是非常简单。

我们用如下一个简单的栗子说明一下吧,做了详细的注释~

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
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css';
// 创建父元素
class ParentCom extends React.Component{
constructor(props){
super(props);
this.state = {
str:null // 待父元素的属性值
}
}
render(){
return (
<div>
<h1>子元素传给父元素一个:{this.state.str}</h1>
<ChildCom change = {this.changeStr}/>{/*将父元素的函数作为参数传给子元素*/}
</div>
)
}
// 使用如下的箭头函数写法就不需要写绑定
changeStr = (data)=>{ // 传入的修改函数,其中设置了参数,用于修改父元素的属性值
this.setState({
str:data
})
}
}
// 创建子元素
class ChildCom extends React.Component{
constructor(props){
super(props);
}
render(){
return(
<div>
<button onClick = {this.clickFunc}>发送给父元素</button>{/*使用这个按钮来调用函数*/}
<input id = 'inputBox' type = 'text'></input>
</div>
)
}
clickFunc = ()=>{ // 调用父元素传入的函数
this.props.change(document.getElementById('inputBox').value);
}
}
ReactDOM.render(<ParentCom />, document.getElementById('root'))

点击按钮就能建文本输入框中的字符串传给父元素了~

wIN52n.png

5.React事件

React事件和html原生事件还要有一些区别的

  1. 绑定事件的命名使用驼峰命名法(小驼峰)
  2. 使用{}传入一个函数,而不是字符串
  3. 事件对象,React返回的事件对象是代理的原生事件对象,如果想要查看事件对象的具体值,必须直接输出事件对象的属性
  4. 代理对象也不能直接通过return flase阻止默认行为,但是能过通过调用函数解决(e.preventDefault())。
  5. 传入参数最好使用箭头函数,匿名函数需要进行绑定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
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css';
class ParentCom extends React.Component{
constructor(props){
super(props);
}
render(){
return(
<div>
<form action = 'https://www.baidu.com/?tn=40039514_2_oem_dg'>
<input id = 'inputBox'></input>
<button onClick = {(e)=>{this.clickFunc(e, document.getElementById('inputBox').value)}}>提交</button>
{/*匿名函数等价写法,需要绑定 <button onClick = {function(e){this.clickFunc(e, document.getElementById('inputBox').value)}.bind(this)}>提交</button> */}
</form>
</div>
)
}
clickFunc = (e, str)=>{
console.log(str); // 传入的字符串
console.log(e);
e.preventDefault(); // 阻止页面跳转
}
}
ReactDOM.render(<ParentCom />, document.getElementById('root'))

可以看到返回的事件对象并不能看到事件的具体值

wIBcbq.png

6.React列表渲染

我们可能有需要将一个数组中的内容渲染在页面中,这时候我们可能就需要用到列表渲染了

6.1 弟中弟版本

我们首先试试直接将数组放置在页面中会怎么样?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css';

let arr = ['Alice','Jack','Bob']; // 待显示的数组

class Display extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<dl>
{arr}
</dl>
</div>
)
}
}

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

可以看到就是简单粗暴的一个一个展开

wIWVJI.png

显然这不是我们想要的效果,聪明的我们立马就想到了,只需要将数组中的元素变成一个一个的JSX对象不就可以了吗?good idea!

1
let arr = [<li>Alice</li>,<li>Jack</li>,<li>Bob</li>];   // 待显示的数组

wIWLX8.png

6.2 弟弟版本

如果我们初始的数组内不是一个一个的JSX对象呢?

那没办法,那就一个一个处理吧~

于是就有了下面的弟弟版本

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
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css';

class Display extends React.Component{
constructor(props){
super(props);
this.state = {
courseArr : [ // 待显示的数组,类似于JSON格式
{
title:'第一节课 计算机组成原理',
content:'内容:忘记了~'
},
{
title:'第二节课 C语言',
content:'内容:排序算法的讲解'
},
{
title:'第三节课 数据解构',
content:'内容:令人头晕的二叉树'
}
]
}
}
render(){
// 使用map函数生成我们想要的结构
let showArr = this.state.courseArr.map((item, index)=>{
return (
<dt key = {index}>
<h3>{item.title}</h3>
<p>{item.content}</p>
</dt>
)
})
return (
<div>
<dl>
<h1>课程记录</h1>
{showArr}
</dl>
</div>
)
}
}

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

6.3 函数版本

如果我们需要渲染的是一个静态列表,那么我们完全可以用函数式组件实现,这里实现和6.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
40
41
42
43
44
45
46
47
48
49
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css';
// 定义一个函数式组件来循环渲染我们的内容
function ListDisplay(props){
return (
<dt key = {props.index}>
<h3>{props.item.title}</h3>
<p>{props.item.content}</p>
</dt>
)
}
class Display extends React.Component{
constructor(props){
super(props);
this.state = {
courseArr : [ // 待显示的数组,类似于JSON格式
{
title:'第一节课 计算机组成原理',
content:'内容:忘记了~'
},
{
title:'第二节课 C语言',
content:'内容:排序算法的讲解'
},
{
title:'第三节课 数据解构',
content:'内容:令人头晕的二叉树'
}
]
}
}
render(){
// 使用map函数生成我们想要的结构
let showArr = this.state.courseArr.map((item, index)=>{
return <ListDisplay key = {index} item = {item} index ={index}></ListDisplay>
})
return (
<div>
<dl>
<h1>课程记录</h1>
{showArr}
</dl>
</div>
)
}
}

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

6.4 类版本

有时候我们可能渲染的列表不是一个静态的内容,可能是一个动态的内容,这时我们就可以使用类组件进行渲染

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
import React from 'react';
import ReactDOM from 'react-dom';
import './panfeng.css';
// 定义一个函数式组件来循环渲染我们的内容
class ListDisplay extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<dt onClick = {()=>{alert('这是第'+String(this.props.index+1)+'节课')}}>
<h3>{this.props.item.title}</h3>
<p>{this.props.item.content}</p>
</dt>
)
}
}
class Display extends React.Component{
constructor(props){
super(props);
this.state = {
courseArr : [ // 待显示的数组,类似于JSON格式
{
title:'第一节课 计算机组成原理',
content:'内容:忘记了~'
},
{
title:'第二节课 C语言',
content:'内容:排序算法的讲解'
},
{
title:'第三节课 数据解构',
content:'内容:令人头晕的二叉树'
}
]
}
}
render(){
// 使用map函数生成我们想要的结构
let showArr = this.state.courseArr.map((item, index)=>{
return <ListDisplay key = {index} item = {item} index ={index}></ListDisplay>
})
return (
<div>
<dl>
<h1>课程记录</h1>
{showArr}
</dl>
</div>
)
}
}

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

这样就为做了一个动态的列表(虽然就是一个小弹窗)

wITHUO.png

7. React入门项目:肺炎数据统计

现成的数据可以在这取:

链接:https://pan.baidu.com/s/1s0H7rGYyrJh5YTPEC2dObw
提取码:x6ug

肺炎数据可以从各个统计网页获得,这里就跳过了

然后就直接上代码吧,其实没有用到什么新的东西,就是一个列表渲染,当然可以选择多种渲染方式(函数组件、类组件都是OK的),这个比较简单,直接看代码也比较轻松~

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
import React from 'react';
import ReactDOM from 'react-dom';
import jsonData from './feiyan3.json' // 导入肺炎数据

console.log(jsonData);
let province ={} // 初步用于保存数据的对象
jsonData.data.list.forEach((item, index)=>{ // 提取各个省份的数据
if(province[item.province] == undefined){ // 如果该省份数据未定义
province[item.province] = {
province:item.province,
confirm:0,
suspect:0,
heal:0,
dead:0
}
}
item.confirm = (item.confirm == null? 0 : item.confirm); // 如果该数据为null,则置为0
item.suspect = (item.suspect == null? 0 : item.suspect);
item.heal = (item.heal == null? 0: item.heal);
item.dead = (item.dead == null? 0 :item.dead);
province[item.province] = {
province:item.province,
confirm:province[item.province].confirm + item.confirm,
suspect:province[item.province].suspect + item.suspect,
heal:province[item.province].heal + item.heal,
dead:province[item.province].dead + item.dead
}
})
let provinceList = []; // 将省份对象数据转化为数组
for(let key in province){
provinceList.push(province[key]);
}
provinceList.sort((a,b)=>{ // 对省份数据进行排序
if(a.confirm < b.confirm){
return 1;
}
return -1;
})
console.log(provinceList);
function Feiyan(props){ // 用函数组件显示数据
//let showArr = []
let showArr = props.province.map((item, index)=>{ // 列表渲染常规操作
return(
<dt key = {index}>
<h3>{item.province}</h3>
<p>确诊人数:{item.confirm} 疑症人数:{item.suspect}</p>
<p>康复人数:{item.heal} 死亡人数:{item.dead}</p>
</dt>
)
})
return(
<div>
<h1>2020中国肺炎数据</h1>
{showArr}
</div>
)
}
ReactDOM.render(<Feiyan province = {provinceList}></Feiyan>, document.getElementById('root'));

显示的效果:

wqKgoQ.png

8.生命周期

生命周期就是组件从实例化到渲染到最终页面中销毁,整个过程就是生命周期,在这生命周期中,我们有许多可以调用的事件,也俗称为钩子函数

生命周期的3个状态:

  1. Mounting:(挂载状态),将组件插入到DOM中
  2. Updating:(更新),将数据更新到DOM中
  3. Unmounting:(卸载),将组件移出DOM

生命周期的钩子函数:

  • componentWillMount 在渲染前调用
  • componentDidMount : 在第一次渲染后调用
  • componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。
  • shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。
    可以在你确认不需要更新组件时使用。
  • componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
  • componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
  • componentWillUnmount在组件从 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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import React,{Component} from 'react';
import ReactDOM from 'react-dom';

class Comlife extends Component{ // 子组件,用于演示钩子函数
constructor(props){
super(props);
this.state = {
msg:''
}
}
componentWillMount(){
console.log('componentWillMount在渲染前调用');
}
componentDidMount(){
console.log('componentDidMount在第一次渲染后调用');
}
componentWillReceiveProps(){
console.log('componentWillReceiveProps在接受到一个新的props时调用');
}
componentWillUpdate(){
console.log('componentWillUpdate在组件更新时调用');
}
componentDidUpdate(){
console.log('componentDidUpdate在组件完成更新后调用');
}
componentWillUnmount(){
console.log('componentWillUnmount在组件从DOM中移除前调用');
}
render(props){
return(
<div>
<h1>Hello {this.props.name + this.state.msg}</h1>
<button onClick = {this.sayHello}>感叹号</button>
</div>
)
}
sayHello = ()=>{
this.setState({
msg:'!'
})
}
}
class ParentCom extends Component{ // 母组件,调用子组件,协助完成钩子函数的展示
constructor(props){
super(props);
this.state = {
showSub:true,
subStr:'xxx'
}
}
render(){
if(this.state.showSub){
return (
<div>
<button onClick = {this.setName}>输入你的姓名</button>
<input id = 'inputBox' type = 'text'></input>
<Comlife name = {this.state.subStr}></Comlife><br></br>
<button onClick = {this.remmove}>给我消失!</button>
</div>
)
}
else{
return (
<h1>消失啦~</h1>
)
}
}
setName = ()=>{
this.setState({
subStr: document.getElementById('inputBox').value
})
}
remmove = ()=>{
this.setState({
showSub : false
})
}
}
ReactDOM.render(<ParentCom></ParentCom>, document.getElementById('root'));

然后生成的页面就如下图所示,然后依次按照顺序点击,就能够看到钩子函数的调用顺序了

wq69nf.png

如下就是钩子函数的调用情况:

wqyg7F.png

9. 中国肺炎疫情小项目

使用前面入门小项目的数据,然后完成一个较为完整的疫情项目(其实非常的简单),算是最近学习的一个总结(准备跑路~),代码链接

最终项目效果:

09BDlF.png

主要有三个功能组件:

  1. 地图组件:用于显示中国地图以及相关数据

09BoOH.png

  1. 搜索组件:用于搜索相关省份的疫情信息,支持子串搜索

09BOtP.png

  1. 表格组件:将疫情数据按照感染人数排序的一个表格信息

09Bx1S.png