组件生命,就是组件在不同阶段提供对应的钩子函数,来处理逻辑操作。比如初始化阶段,我们需要初始化组件相关的状态和变量。组件销毁阶段时,我们需要把一些数据结构销毁来节约内存。
React组件生命周期分为三个阶段:挂载阶段【Mount】、更新阶段【Update】和卸载阶段【Umount】。
组件挂载阶段
挂载阶段,就是组件实例化并且挂载到DOM树的这个过程。在这个阶段中依次调用生命周期函数为:
- constructor()
- getDerivedStateFromProps()
- render()
- componentDidMount()
constructor(props)
constructor,是构造函数,用来初始化组件的状态和操作。React类组件一般是通过继承React.Component来创建的,所以需要调用super(props),初始化父类。
在constructor函数中,我们可以初始化state,同时可以对操作函数进行bind绑定。但是需要注意的是,不能在constructor中调用setState,否则会报错,因为setState是用来更新状态的。
操作函数绑定如下:
import React from "react";
interface PropsType {
name: string;
}
class App extends React.Component<any, PropsType> {
constructor(props: any) {
super(props);
this.state = {
name: "Duxinyues",
};
this.handle.bind(this);
}
handle = function(param:any) {
console.log(param);
};
render(): React.ReactNode {
console.log("this.state", this.state);
const { name } = this.state;
return (
<div>
{name}
<button onClick={()=>this.handle(345)}>点击</button>
</div>
);
}
}
export default App;
如果在不想在constructor中绑定this的话,也可以在使用操作函数的时候绑定this。比如:
<button onClick={this.handle.bind(this,423)}>点击</button>
或者使用箭头函数来定义操作函数,因为箭头函数的this指向的是它定义时所在的上下文环境,而不是指向它的调用者。
handle = (param:any) =>{
console.log(param);
};
当然,也可以不用再constructor中初始化状态,组件会默认初始化的。
getDerivedStateFromProps()
这个生命周期函数是在初始化后或者是在更新阶段中,接收新props后返回一个对象作为新的state。如果返回的是null,那么说明组件不用更新state。
另外,getDerivedStateFromProps()是static方法,在内部是不能获取到this的。
render
render方法是根据状态state和属性props来渲染组件。如果state和props不变,那么render返回的结果都是一样。需要注意的是不要在render方法内改变组件状态,也不要在render方法内直接个浏览器进行交互。
componentDidMount()
componentDidMount函数在组件挂载后调用,也就是在render方法后调用,而且是在组件整个生命周期内只调用一次。一般情况下,我们会在这个方法内进行网络请求等等。
更新阶段
当组件的状态或者属性变化的时候,会导致组件更新,依次调用生命周期函数:
- getDerivedStateFromProps()
- componentWillUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
shouldComponentUpdate(nextProps,nextState)
在组件更新之前,我们可以通过shouldComponentUpdate()函数来判断组件是否需要更新,它默认返回true,每次状态和属性发生变化的时候,组件都重新render一下。如果返回false,那么组件就不会更新。
另一种方法就是用React.PureComponent来创建组件,PureComponent默认进行state和props的比较这是组件优化的一种手段。
getSnapshotBeforeUpdate()
这个方法是在render之后,dom渲染之前返回一个值,作为componentDidUpdate函数的第三个参数,比如官方的例子:
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>
);
}
}
在上述示例
卸载阶段
componentWillUnmount(),这个方法在组件卸载阶段中调用
捕获错误
React有一个生命周期函数componentDidCatch(error,info)。
React组件产生错误没有被捕获,那么就抛给上层组件,如果上层组件也没有捕获,就会抛到顶层组件,最终导致浏览器白屏。