react基础(二)
react生命周期 搞起来
# react组件的生命周期
# react 17生命周期的变化
起先对着网上博客文章一顿看,然后动手敲起来,才发现有的生命周期在vscode中的代码提示里已经被置灰了。
去官网看了一下文档才发现,原来这两年react大版本已经更新到v17了,生命周期已经和几年前的那些博客中所提的有了较大改变。所以说学习新知识最好的途径还是官方文档,其次才是别人的经验。
然后先附上两张图,分别对应之前版本和此刻v17版本的react周期的变化,或许未来又会有不同。
老版本生命周期:
v17中版本的生命周期:
从图中首先可以看出新版本中
- 剔除了三个生命周期
componentWillMount、componentWillUpdate、compontentWillReceiveProps。 - 新加入了两个生命周期静态的
getDerivedStateFromProps和getSnapshotBeforeUpdate。
其实在react 17版本中剔除的这三个生命周期并不是从react中删除了,我敲了一下发现它们还是存在的,只是官方不在建议使用他们。剔除原因,移步官网 (opens new window)
# 挂载阶段
# constructor()
在react组件挂载之前,会调用它的构造函数。在为React.Component子类实现构造函数时,应在其他语句之前前调用super(props)。否则, this.props在构造函数中可能会出现未定义的bug。
通常,在 React 中,构造函数仅用于以下两种情况:
- 通过
this.state赋值对象来初始化内部state,在constructor()函数中不要调用setState()方法。 - 为
事件处理函数绑定实例。
# componentDidMount()
componentDidMount()会在组件挂载后(插入DOM树中)立即调用。依赖于DOM节点的初始化应该放在这里。请求后台接口的操作可以放到这个生命周期内执行。在这个生命周期内同时也适合添加订阅,但要记得在componentWillUnmount()周期内取消订阅。
在这个生命周期内可以使用setState()方法来改变组件的state的属性值,它将触发额外渲染,但它发生在浏览器更新屏幕前,因此用户不会看出中间状态。
通过这两个生命周期,我们就可以实现从后台接收数据渲染到页面的操作:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { queryLabelInfo } from '../api/test'
class List extends Component {
constructor() {
super();
this.state = {
list: []
};
};
componentDidMount() {
// 请求后台接口
queryLabelInfo({ current: 1, size: 10})
.then(res => {
this.setState({
list: res.data.records
})
})
};
render() {
return (
<div>
<div>
{
this.state.list.map(item => {
return <div key={item.id}>{item.typeName}</div>
})
}
</div>
</div>
)
}
}
ReactDOM.render(
<List />,
document.getElementById('root')
);
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
效果如图:
# static getDerivedStateFromProps()
getDerivedStateFromProps会在调用render方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新state,如果返回null则不更新任何内容。
这个生命周期中无权访问组件实例。如果需要,可以通过提取组件props的纯函数及class之外的状态,在getDerivedStateFromProps()和其他class方法之间重用代码。
# 更新阶段
# shouldComponentUpdate()
根据shouldComponentUpdate()的返回值,判断React组件的输出是否受当前state或props更改的影响。默认行为是state每次发生变化组件都会重新渲染。
当props或state发生变化时shouldComponentUpdate()会在渲染执行之前被调用。返回true则更新视图,返回false则不更新视图。返回值默认为true。首次渲染或使用forceUpdate()方法时不会调用该方法。
案例:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Counter extends Component {
constructor() {
super();
this.state = {
count: 0,
};
};
//返回false视图不在更新 ture则更新
shouldComponentUpdate(newProps, newState) {
if(newState.count > 3) {
return false
}
return true
};
add() {
this.setState({
count: this.state.count + 1
})
console.log('count已增加,值为:', this.state.count)
};
render() {
return (
<div>
<span>{this.state.count}</span>
<button onClick={this.add.bind(this)}>+</button>
</div>
)
};
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
}
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
# getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate()在最近一次渲染输出(提交到DOM节点)之前调用。它使得组件能在发生更改之前从DOM中捕获一些信息(例如,滚动位置)。此生命周期的任何返回值将作为参数传递给 componentDidUpdate()。返回值应为snapshot的值(或null)
这个暂时不知道有什么使用场景,官网示例:
class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
// 我们是否在 list 中添加新的 items ?
// 捕获滚动位置以便我们稍后调整滚动位置。
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
// 如果我们 snapshot 有值,说明我们刚刚添加了新的 items,
// 调整滚动位置使得这些新 items 不会将旧的 items 推出视图。
//(这里的 snapshot 是 getSnapshotBeforeUpdate 的返回值)
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}
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
在上述示例中,重点是从 getSnapshotBeforeUpdate 读取 scrollHeight 属性,因为 “render” 阶段生命周期(如 render)和 “commit” 阶段生命周期(如 getSnapshotBeforeUpdate 和 componentDidUpdate)之间可能存在延迟。
# componentDidUpdate()
componentDidUpdate(prevProps, prevState, snapshot)会在更新后立刻被执行,但首次渲染不会执行此方法。
这里可以对比更新前后的props和state,然后进行相应操作,如网络请求或者调用setState方法。但要注意一定要对比变化,放在条件语句中中执行,否则可能会反复执行导致死循环
- 最好不要此生命周期内调用
setState; - 第一次初始化组件时,此方法不会执行;
- 当
shouldComponentUpdate返回false时此方法同样不会执行。
# 卸载阶段
# componentWillUnmount()
componentWillUnmount()会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除timer,取消网络请求或清除在componentDidMount()中创建的订阅等。
componentWillUnmount()中不应调用setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
# componentDidCatch(error, info)
当组件发生异常时会被调用的钩子。 它接收两个参数:
- error —— 抛出的错误。
- info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。
注意点:
- 只能在父级组件捕获子组件的异常;
- 如果异常被
try...catch包裹父级组件的钩子就不会执行了。
# 小结
今天学习了react生命周期,联系vue
constructor相当于vue的created,组件还未挂载,dom元素还不可访问,可以进行一些数据处理;componentDidMount相当于vue的mounted,组件完成挂载,可以对dom元素进行操作;componentDidUpdate相当于vue的updated,由于数据更新导致重新渲染时被调用的钩子;componentWillUnmount相当于vue的beforeDestroy,组件从dom中移除时会触发的钩子;getDerivedStateFromProps、shouldComponentUpdate、getSnapshotBeforeUpdate似乎在vue中没有对照。
- 01
- 2021/10/23 00:00:00
- 02
- 2021/08/18 17:00:03
- 03
- 2021/07/04 15:26:36
