故事: 以下都是拾人牙慧,主要是方便自己的学习总结,
组件初始化 constructor
React借用class类的constructor充当初始化钩子。
React几乎没做什么手脚,但是因为我们只允许通过特定的途径给组件传递参数,所以constructor的参数实际上是被React规定好的。
React规定constructor有三个参数,分别是props、context和updater。
props是属性,它是不可变的
context是全局上下文
updater是包含一些更新方法的对象
this.setState最终调用的是this.updater.enqueueSetState方法
this.forceUpdate最终调用的是this.updater.enqueueForceUpdate方法
所以这些API更多是React内部使用,暴露出来是以备开发者不时之需。 在React中,因为所有class组件都要继承自Component类或者PureComponent类,因此和原生class写法一样,要在constructor里首先调用super方法,才能获得this。
constructor生命周期钩子的最佳实践是在这里初始化this.state,而且禁止在构造函数中调用setState,可以直接给state设置初始值
当然,你也可以使用属性初始化器来代替,如下:
import React, { Component } from 'react';
class App extends Component {
state = {
name: 'biu'
};
}
export default App;组件挂载
1)componentWillMount()
注意(这是React不再推荐使用的API。)
其实componentWillMount和挂载是同步执行的,意味着执行完这个钩子,立即挂载。而向服务器请求数据是异步执行的。所以无论请求怎么快,都要排在同步任务之后再处理,这是辈分问题。 也就是说,永远不可能在这里将数据插入元素一同挂载。 并不是说不能在这里请求数据,而是达不到你臆想的效果。
它被废弃的原因主要有三点:
本来它就没什么用。估计当初是为了成双成对所以才创造了它吧。
如果它声明了定时器或者订阅器,在服务端渲染中,componentWillUnmount生命周期钩子中的清除代码不会生效。因为如果组件没有挂载成功,componentWillUnmount是不会执行的。
在异步渲染中,它的表现不稳定,因此在componentWillMount里做 AJAX 请求实在不是一个明智之举,因为对于同构项目中,componentWillMount是会被调用的。
初始化this.state应该在constructor生命周期钩子中完成,请求数据应该在componentDidMount生命周期钩子中完成,所以它不仅被废弃了,连继任者都没有。
综上所述,componentWillMount其实本来没有什么主要作用,如果你的代码规范,去掉的话,不会对现在的项目产生什么影响。
static getDerivedStateFromProps(nextProps, prevState)
一个静态方法,所以不能在这个函数里面使用this,这个函数有两个参数props和state,分别指接收到的新参数和当前的state对象,这个函数会返回一个对象用来更新当前的state对象,如果不需要更新可以返回null
2)render()
作为一个组件,最核心的功能就是把元素挂载到DOM上,所以render生命周期钩子是一定会用到的。
render生命周期钩子怎么接收模板呢?当然是你return给它。
但是不推荐在return之前写过多的逻辑,如果逻辑过多,可以封装成一个函数。
render() {
// 这里可以写一些逻辑
return (
<div>生命周期</div>
)
}注意,千万不要在render生命周期钩子里调用this.setState,因为this.setState会引发render,这下就没完没了了。
3)componentDidMount [非常重要的钩子]
这是组件挂载到DOM之后的生命周期钩子。
这可能是除了render之外最重要的生命周期钩子,因为这时候组件的各方面都准备就绪,天地任你闯。
组件更新
1)componentWillReceiveProps(nextProps)
注意:是React不再推荐使用的API。
componentWillReceiveProps生命周期钩子只有一个参数,更新后的props。
该声明周期函数可能在两种情况下被触发:
组件接收到了新的属性。
组件没有收到新的属性,但是由于父组件重新渲染导致当前组件也被重新渲染。
初始化时并不会触发该生命周期钩子。
同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次触发。
getDerivedStateFromProps
这个方法在装载阶段已经讲过了,这里不再赘述,记住在更新阶段,无论我们接收到新的属性,调用了setState还是调用了forceUpdate,这个方法都会被调用
2)shouldComponentUpdate(nextProps, nextState)
这个生命周期钩子是一个开关,判断是否需要更新,主要用来优化性能。 有一个例外,如果开发者调用this.forceUpdate强制更新,React组件会无视这个钩子。
shouldComponentUpdate生命周期钩子默认返回true。也就是说,默认情况下,只要组件触发了更新,组件就一定会更新。React把判断的控制权给了开发者。
不过周到的React还提供了一个PureComponent基类,它与Component基类的区别是PureComponent自动实现了一个shouldComponentUpdate生命周期钩子。
对于组件来说,只有状态发生改变,才需要重新渲染。所以shouldComponentUpdate生命周期钩子暴露了两个参数,开发者可以通过比较this.props和nextProps、this.state和nextState来判断状态到底有没有发生改变,再相应的返回true或false
export default class Life extends React.Component {
constructor(props) {
super(props)
this.state = {
count:1
}
}
shouldComponentUpdate(nextProps, nextState) {
//接受两个参数
//返回true则表示通过比较新返回的元素和之前渲染的元素,两者不相等,此时更新DOM
return true
}
handleClick = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
// 这里可以写一些逻辑
console.log(this.state.count)
return (
<div>
<div>生命周期</div>
<button onClick={this.handleClick}>{this.state.count}</button>
</div>
)
}
}3)componentWillUpdate(nextProps, nextState)
注意:这是React不再推荐使用的API。
shouldComponentUpdate生命周期钩子返回true,或者调用this.forceUpdate之后,会立即执行该生命周期钩子。
要特别注意,componentWillUpdate生命周期钩子每次更新前都会执行,所以在这里调用this.setState非常危险,有可能会没完没了。
同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次调用。
getSnapshotBeforeUpdate(prevProps, prevState)
在 React 更新 DOM 之前调用,此时state已更新; 返回值作为componentDidUpdate的第3个参数; 一般用于获取render之前的 DOM 数据
4)componentDidUpdate(nextProps, nextState, snapshot)
这是组件更新之后触发的生命周期钩子。
搭配getSnapshotBeforeUpdate生命周期钩子使用的时候,第三个参数是getSnapshotBeforeUpdate的返回值。
同样的,componentDidUpdate生命周期钩子每次更新后都会执行,所以在这里调用this.setState也非常危险,有可能会没完没了。
更新 生命周期函数的执行顺序
- static getDerivedStateFromProps
- shouldComponentUpdate
render
- getSnapshotBeforeUpdate
- componentDidUpdate
组件卸载
componentWillUnmount()
这是组件卸载之前的生命周期钩子。
为什么组件快要卸载了还需要沉思时刻呢?
因为开发者要擦屁股吖。
React的最佳实践是,组件中用到的事件监听器、订阅器、定时器都要在这里销毁。
当然我说的事件监听器指的是这种:
componentDidMount() {
document.addEventListener('click', () => {});
}因为下面这种React会自动销毁,不劳烦开发者了。
render() {
// 这里可以写一些逻辑
return (
<div>
<div>生命周期</div>
<button onClick={this.handleClick}>{this.state.count}</button>
</div>
)
}整理V16 生命周期函数用法建议
class ExampleComponent extends React.Component {
// 用于初始化 state
constructor() {}
// 用于替换 `componentWillReceiveProps` ,该函数会在初始化和 `update` 时被调用
// 因为该函数是静态函数,所以取不到 `this`
// 如果需要对比 `prevProps` 需要单独在 `state` 中维护
static getDerivedStateFromProps(nextProps, prevState) {}
// 判断是否需要更新组件,多用于组件性能优化
shouldComponentUpdate(nextProps, nextState) {}
// 组件挂载后调用
// 可以在该函数中进行请求或者订阅
componentDidMount() {}
// 用于获得最新的 DOM 数据
getSnapshotBeforeUpdate() {}
// 组件即将销毁
// 可以在此处移除订阅,定时器等等
componentWillUnmount() {}
// 组件销毁后调用
componentDidUnMount() {}
// 组件更新后调用
componentDidUpdate() {}
// 渲染组件函数
render() {}
// 以下函数不建议使用
UNSAFE_componentWillMount() {}
UNSAFE_componentWillUpdate(nextProps, nextState) {}
UNSAFE_componentWillReceiveProps(nextProps) {}
}