跳到主要内容

React:组件生命周期管理

· 阅读需 6 分钟

组件生命,就是组件在不同阶段提供对应的钩子函数,来处理逻辑操作。比如初始化阶段,我们需要初始化组件相关的状态和变量。组件销毁阶段时,我们需要把一些数据结构销毁来节约内存。

React组件生命周期分为三个阶段:挂载阶段【Mount】、更新阶段【Update】和卸载阶段【Umount】。

组件挂载阶段

挂载阶段,就是组件实例化并且挂载到DOM树的这个过程。在这个阶段中依次调用生命周期函数为:

  1. constructor()
  2. getDerivedStateFromProps()
  3. render()
  4. 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方法后调用,而且是在组件整个生命周期内只调用一次。一般情况下,我们会在这个方法内进行网络请求等等。


更新阶段

当组件的状态或者属性变化的时候,会导致组件更新,依次调用生命周期函数:

  1. getDerivedStateFromProps()
  2. componentWillUpdate()
  3. render()
  4. getSnapshotBeforeUpdate()
  5. 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组件产生错误没有被捕获,那么就抛给上层组件,如果上层组件也没有捕获,就会抛到顶层组件,最终导致浏览器白屏。