1、前言
React 组件的生命周期根据广义定义描述,可以分为挂载、渲染和卸载这几个阶段。当渲染后的组件需要更新新时,我们会重新去渲染组件,直至卸载。
因此,我们可以把 React 生命周期分成两类:
- 当组件在挂载或卸载时;
- 当组件接收新的数据时,即组件更新时。
2、挂载或卸载过程
2.1 组件的挂载
组件挂载是最基本的过程,这个过程主要做组件状态的初始化
import React, {Component} from 'react';
import './App.css';
class App extends Component {
//打印顺序
//App constructor
// App componentWillMount
// app render
//App componentDidMount
static propTypes = {
}
static defaultProps = {
}
constructor(props) {
super(props);
this.state = {
count: 0
}
// 重点在这里
this.handleClick = this.handleClick.bind(this);
console.log('App constructor')
}
componentWillMount() {
console.log('App componentWillMount')
}
render() {
console.log('app render')
return <a href="#" onClick={this.handleClick}>Clicked me {this.state.count} times.</a>
}
componentDidMount() {
console.log('App componentDidMount')
}
handleClick(e) {
e.preventDefault();
this.setState({ count: this.state.count + 1 })
}
}
export default App;
特点:
- propTypes 和 defaultProps 分别代表 props 类型检查和默认类型。这两个属性被声明成静态属性,意味着从类外面也可以访问它们,比如可以这么访问:App.propTypes 和 App.defaultProps。
- componentWillMount 方法会在 render 方法之前执行,而 componentDidMount 方法会在 render 方法之后执行,分别代表了渲染前后的时刻
- 读取初始 state 和 props 以及两个组件生命周期方法componentWillMount 和 componentDidMount,这些都只会在组件初始化时运行一次。
2.2 组件的卸载
组件卸载非常简单,只有 componentWillUnmount 这一个卸载前状态
export default class A extends React.Component {
constructor(props) {
super(props);
}
scroll1(){}
componentDidMount() {
window.addEventListener('scroll', this.srcoll1.bind(this));
}
componentWillUnmount(){
window.removeEventListener('scroll', this.srcoll1);
}
render() {
};
}
在 componentWillUnmount 方法中,我们常常会执行一些清理方法,如事件回收或是清除定时器。
3、 数据更新过程
更新过程指的是父组件向下传递 props 或组件自身执行 setState 方法时发生的一系列更新动作。这里我们屏蔽了初始化的生命周期方法,以便观察更新过程的生命周期:
import React, {Component} from 'react';
import './App.css';
class App extends Component {
/*在shouldComponentUpdate,里设置return true 点击handleClick时打印顺序
{} {count: 1} "shouldComponentUpdate"
{} {count: 1} "componentWillUpdate"
app render
{} {count: 0} "componentDidUpdate"*/
/*在shouldComponentUpdate,里设置return false 点击handleClick时打印顺序
{} {count: 1} "shouldComponentUpdate"
this.state.count没有变*/
constructor(props) {
super(props);
this.state = {
count: 0
}
this.handleClick = this.handleClick.bind(this);
}
render() {
console.log('app render')
return <a href="#" onClick={this.handleClick}>Clicked me {this.state.count} times.</a>
}
componentWillReceiveProps(nextProps) {
console.log(nextProps,'componentWillReceiveProps')
}
shouldComponentUpdate(nextProps, nextState) {
console.log(nextProps,nextState,'shouldComponentUpdate')
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log(nextProps,nextState,'componentWillUpdate')
// ...
}
componentDidUpdate(prevProps, prevState) {
console.log(prevProps,prevState,'componentDidUpdate')
// ...
}
handleClick(e) {
e.preventDefault();
this.setState({ count: this.state.count + 1 })
}
}
export default App;
特点
- 组件自身的 state 更新了,那么会依次执行 shouldComponentUpdate、componentWillUpdate 、render 和 componentDidUpdate
- shouldComponentUpdate 是一个特别的方法,它接收需要更新的 props 和 state,让开发者增加必要的条件判断,让其在需要时更新,不需要时不更新。因此,当方法返回 false 的时候,组件不再向下执行生命周期方法
- component-WillUpdate 方法代表在更新过程中渲染前的时刻,提供需要更新的 props 和 state。
- componentDidUpdate代表在更新过程中渲染后的时刻 提供更新前的 props 和state。
3.1 componentWillReceiveProps 方法
如果组件是由父组件更新 props 而更新的,那么在 shouldComponentUpdate 之前会先执行componentWillReceiveProps 方法。此方法可以作为 React 在 props 传入后,渲染之前 setState 的机会。在此方法中调用 setState 是不会二次渲染的.
import React, {Component} from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
activeIndex: 0,
};
}
handleChange(e) {
this.setState({
activeIndex: parseInt(e.target.value, 10),
});
}
render() {
return (
<div>
<select value={this.state.activeIndex} onChange={this.handleChange}>
<option value="1">Tab 1</option>
<option value="2">Tab 2</option>
<option value="3">Tab 3</option>
</select>
<Hello defaultActiveIndex={this.state.activeIndex} className="tabs-bar"></Hello>
</div>
)
}
}
class Hello extends React.Component{
constructor(props){
console.log('hello constructor')
super(props);
this.state = {
activeIndex:11,
};
}
componentWillReceiveProps(nextProps) {
if ('defaultActiveIndex' in nextProps) {
console.log(nextProps.defaultActiveIndex,444)
this.setState({
activeIndex: nextProps.defaultActiveIndex,
});
}
}
render(){
return <div>{this.props.defaultActiveIndex} + {this.state.activeIndex}</div>
}
}
export default App;
目的是让传入的 props 判断是否存在 activeIndex。如果用了 activeIndex 初始化组件,那么每次组件更新前都会去更新组件内部的 activeIndex state,达到更新组件的目的。
4、React与vue的生命周期对照
4.1 组件挂载阶段
mounted,视图渲染完毕后,在这个阶段获取数据,同componentDidMount
4.2 组件更新阶段
4.3 组件卸载阶段