React 生命周期
Galloping_Leo 2020-09-29 React
# React 生命周期

# class组件生命周期
注意:只有 class 组件才会有生命周期
# 挂载阶段
constructor
render
componentDidMount
- 发送ajax请求
- 操作DOM
- ...
class Hello extends React.Component {
// 最早执行:
// 1 初始化state
// 2 给事件处理程序绑定 this
constructor(props) {
super(props)
console.warn('1 组件生命周期钩子函数: constructor')
}
// 作用1:可以用来在进入页面时(该组件渲染时),发送ajax请求
// 作用2:可以操作DOM(因为 render 已经将 JSX 渲染到页面中了)
componentDidMount() {
console.warn(
'3 组件生命周期钩子函数: componentDidMount',
(document.getElementsByTagName('h1')[0].style.color = 'red')
)
}
// 作用:渲染 UI,负责将 JSX 渲染到页面中
// 注意:不要在 render 方法中调用 setState() 方法,否则,会造成死循环!
render() {
// this.setState({})
console.warn('2 组件生命周期钩子函数: render')
return (
<div>
<h1>class 组件</h1>
</div>
)
}
}
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
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
# 更新阶段
getDerivedStateFromProps
将获取到的参数 props
设置到 state
中供组件使用。这样做的好处:在组件中全使用 state
中的数据,避免有 props
和 state
产生混乱。
有两个参数 nextProps
下一次的 props
值, preState
上一次的 state
值
注意
必须返回一个对象,此对象作为新的
state
使用。此方法是一个静态方法。使用时加上
static
关键字。
import React from 'react';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { number: 0 };
}
handler = () => {
this.setState({
number: this.state.number + 1
})
}
render() {
return (
<React.Fragment>
{this.state.number}
<button onClick={this.handler}>+</button>
<Sub number={this.state.number} />
</React.Fragment>
);
}
}
class Sub extends React.Component {
constructor(props) {
super(props)
this.state = { number: this.props.number }
}
// 将属性得到的值 派生为 state 中的值,使用的使用的时候避免混乱,统一成state,统一使用state避免混乱
//必须有返回值
static getDerivedStateFromProps(nextP, preS) {
if (nextP.number % 2 === 0) {
return { number: nextP.number * 2 }
} else {
return { number: nextP.number * 3 }
}
}
render() {
return <div>sub:{this.state.number}</div>
}
}
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
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
render
( 同挂载阶段的 render
)
componentDidUpdate
导致组件更新的三种情况:
- 1
setState()
- 2 组件接收到新的
props
- 3
forceUpdate()
注意:不管是 函数组件 还是 类组件,只要接收到新的 props
,那么,组件都会重新渲染
class Hello extends React.Component {
state = {
count: 0
}
// 第一个参数:表示上一次的 props
// 第二个参数:表示上一次的 state
// 说明:可以在该钩子函数中调用 setState(),但是,一定要把 setState() 放在一个条件判断中
// 比如:可以对比更新前后的 props 是否相同,或者 对比更新前后的 状态是否相同
// 注意:不要直接调用 setState() 否则,会造成死循环
componentDidUpdate(prevProps, prevState) {
console.warn(
'2 组件生命周期钩子函数: componentDidUpdate',
document.getElementsByTagName('h1')[0].innerText,
prevProps,
prevState
)
// 如何获取最新的props 和 最新的state?
console.log(this.props, this.state)
}
handleClick = () => {
this.setState({
count: this.state.count + 1
})
// 强制组件更新(知道即可):
// forceUpdate()
// this.forceUpdate()
}
render() {
console.warn('1 组件生命周期钩子函数: render')
return (
<div>
<Child count={this.state.count} />
<button onClick={this.handleClick}>更新组件</button>
</div>
)
}
}
// 当组件接收到新的 props 值时,也会触发组件更新
class Child extends React.Component {
componentDidUpdate() {
console.warn('子组件 -> 的生命周期钩子函数: componentDidUpdate')
}
render() {
console.warn('子组件 -> 的生命周期钩子函数: render')
return <h1>计数器:{this.props.count}</h1>
}
}
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
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
getSnapshotBeforeUpdate
获取组件将要更新前的快照信息,必须返回一个值数据 res
, 作为 componentDidUpdate
的第三个参数传入。根据更新前的 res
在更新后进行处理。
import React from 'react';
import PropTypes from 'prop-types';
export default class App extends React.Component {
constructor(props) {
super(props);
this.wrapper = React.createRef()
this.state = { msgList: [] };
}
componentDidMount() {
setInterval(() => {
this.setState({ msgList: [this.state.msgList.length, ...this.state.msgList] })
}, 1000 * 1)
}
getSnapshotBeforeUpdate() {
// 返回更新前内容高度 ,在 componentDidUpdate 第三个参数中获取
return this.wrapper.current.scrollHeight
}
componentDidUpdate(prevP, prevS, preScrollHeight) {
this.wrapper.current.scrollTop = this.wrapper.current.scrollTop + (this.wrapper.current.scrollHeight - preScrollHeight)
}
render() {
let style = {
width: 200,
height: 100,
overflow: 'auto',
border: '1px solid red'
}
return (
<div style={style} ref={this.wrapper}>
{this.state.msgList.map((item, index) => <li key={item}>{item}</li>)}
</div>
);
}
}
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
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
# 卸载阶段
触发时机:组件卸载,也就是从页面中消失的时候
componentWillUnmount
- 作用:执行清理工作,比如:清理定时器、给window绑定的事件等,我们手动开启的操作
// 当组件从页面中消失,此时,就会触发组件的卸载阶段
class Child extends React.Component {
componentDidMount() {
// 开启定时器
// this.timerId = setInterval(() => {
// console.log('定时器触发了')
// }, 1000)
window.addEventListener('resize', this.handleResize)
}
handleResize = () => {
console.log('窗口大小改变了')
}
// 组件将要卸载
componentWillUnmount() {
console.warn('组件生命周期钩子函数: componentWillUnmount')
// 清理定时器
// clearInterval(this.timerId)
window.removeEventListener('resize', this.handleResize)
}
render() {
return <h1>统计豆豆被打的次数:{this.props.count}</h1>
}
}
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
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