组件初始化
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。
当然,你也可以使用属性初始化器来代替,如下:
import React, { Component } from 'react';class App extends Component { state = { name: 'biu', };}export default App;复制代码
组件挂载
1)componentWillMount()
注意(这是React不再推荐使用的API。)
其实componentWillMount和挂载是同步执行的,意味着执行完这个钩子,立即挂载。而向服务器请求数据是异步执行的。所以无论请求怎么快,都要排在同步任务之后再处理,这是辈分问题。 也就是说,永远不可能在这里将数据插入元素一同挂载。 并不是说不能在这里请求数据,而是达不到你臆想的效果。
它被废弃的原因主要有三点:
本来它就没什么用。估计当初是为了成双成对所以才创造了它吧。
如果它声明了定时器或者订阅器,在服务端渲染中,componentWillUnmount生命周期钩子中的清除代码不会生效。因为如果组件没有挂载成功,componentWillUnmount是不会执行的。姚明说的:没有挂载就没有卸载。
在异步渲染中,它的表现不稳定。
初始化this.state应该在constructor生命周期钩子中完成,请求数据应该在componentDidMount生命周期钩子中完成,所以它不仅被废弃了,连继任者都没有。
2)render()
作为一个组件,最核心的功能就是把元素挂载到DOM上,所以render生命周期钩子是一定会用到的。 render生命周期钩子怎么接收模板呢?当然是你return给它。 但是不推荐在return之前写过多的逻辑,如果逻辑过多,可以封装成一个函数。
render() { // 这里可以写一些逻辑 return (生命周期)}复制代码
注意,千万不要在render生命周期钩子里调用this.setState,因为this.setState会引发render,这下就没完没了了。
3)componentDidMount
这是组件挂载到DOM之后的生命周期钩子。 这可能是除了render之外最重要的生命周期钩子,因为这时候组件的各方面都准备就绪,天地任你闯。
组件更新
1)componentWillReceiveProps(nextProps)
注意:是React不再推荐使用的API。
componentWillReceiveProps生命周期钩子只有一个参数,更新后的props。
该声明周期函数可能在两种情况下被触发:
组件接收到了新的属性。
组件没有收到新的属性,但是由于父组件重新渲染导致当前组件也被重新渲染。
初始化时并不会触发该生命周期钩子。 同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次触发。
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 () }}复制代码生命周期
3)componentWillUpdate(nextProps, nextState)
注意:这是React不再推荐使用的API。
shouldComponentUpdate生命周期钩子返回true,或者调用this.forceUpdate之后,会立即执行该生命周期钩子。 要特别注意,componentWillUpdate生命周期钩子每次更新前都会执行,所以在这里调用this.setState非常危险,有可能会没完没了。 同样,因为Fiber机制的引入,这个生命周期钩子有可能会多次调用。
4)componentDidUpdate(nextProps, nextState, snapshot)
这是组件更新之后触发的生命周期钩子。 搭配getSnapshotBeforeUpdate生命周期钩子使用的时候,第三个参数是getSnapshotBeforeUpdate的返回值。 同样的,componentDidUpdate生命周期钩子每次更新后都会执行,所以在这里调用this.setState也非常危险,有可能会没完没了。
组件卸载
componentWillUnmount()
这是组件卸载之前的生命周期钩子。 为什么组件快要卸载了还需要沉思时刻呢? 因为开发者要擦屁股吖。 React的最佳实践是,组件中用到的事件监听器、订阅器、定时器都要在这里销毁。 当然我说的事件监听器指的是这种:
componentDidMount() { document.addEventListener('click', () => {});}复制代码
因为下面这种React会自动销毁,不劳烦开发者了。
render() { // 这里可以写一些逻辑 return ()}复制代码生命周期