首先,我们来看一张官方的生命周期图
很多人,看到这张图的时候,都是一脸懵逼的,因为他是把所有生命周期所出现的所有场景整合在一起的,初学者难免会有点混乱,接下来,我会通过代码加场景,跟大家一一的过一遍。
挂载过程
1.constructor()
react的初始化函数,它完成了react数据的初始化,接受一个props参数,如果想要在constructor函数中使用父组件传递过来的props的时候,就需要在super里面传递这个参数。
在我的另外一篇关于constructor的文章中也提到了,如果不定义constructor的话,class会默认生成一个,但是如果定义了,需要在页面中使用this的时候,就需要constructor中调用super,而如果在constructor需要用到props,那么久需要把props当初参数传递给super()
2.componentWillMount()
组件经过了constructor初始化函数,数据将要挂载的时候触发,要注意,此时dom元素还没有渲染,在这个函数里面使用refs,是拿不到dom元素的
3.render
渲染组件的函数,在这个函数里会把初始化好的数据,渲染到组件里面。每一次数据更新的时候,这个函数就会执行一遍。
即:当组件的state或者props发生改变的时候,render函数就会重新执行
当父组件的render函数被运行时,它的子组件的render都将被重新运行一次
所以为了性能上的优化,render里面,尽量不要写逻辑操作。当然也不能在这个函数里面修改state数据,否则就会陷入死循环(state初始化–>触发render–>render修改state–>state改变–>触发render–>render修改state…)
4.componentDidMount()
组件挂载完成的时候触发,此时dom元素已经生成。我们一般都会在这个函数里面调用ajax函数。
总体代码如下
export default class Test extends Component {
constructor() {
super()
console.log("第一步,构造函数")
}
componentWillMount() {
console.log("第二步,组件将要被挂载")
}
render() {
console.log("第三步,组件被挂载")
return (
<div>
</div>
)
}
componentDidMount() {
console.log("第四步,组件挂载完成")
}
}
控制台
第一步,构造函数
第二步,组件将要被挂载
第三步,组件被挂载
第四步,组件挂载完成
组件更新过程
1.shouldComponentUpdate
是否要更新数据。
这个函数返回一个布尔值,
如果返回true,表示 可以更新数据,函数就可以往下执行,即可以继续执行componentWillUpdate和render和componentDidUpdate
返回false,就不更新数据,那么在这个函数后面的生命周期函数,就不会执行。
这个函数还接收两个参数,nextProps以及nextState,即更新后的父组件传过来的值以及更新后的state的值
因为,我们可以在这个生命周期里面,做性能优化:比较一下更新后的nextState的值,与原来的state的值是否一致,如果是一致的,那么就返回false,即不继续向下执行,不重新更新render
2.componentWillUpdate
函数将要被更新的时候触发,这个函数用的不多
3.componentDidUpdate
函数更新完成之后触发,如果我们需要更新完成某些数据之后,再执行某些操作,就可以写在这个函数里面
总体代码如下
export default class Test extends Component {
constructor() {
super()
this.state = {
msg: 111
}
}
handleChangeMsg = () => {
this.setState({
msg: 222
})
}
render() {
console.log("组件渲染")
return (
<div>
<div>{this.state.msg}</div>
<button onClick={this.handleChangeMsg}>修改数据</button>
</div>
)
}
shouldComponentUpdate(nextProps, nextState) {
console.log("是否更新组件")
console.log(nextProps, nextState)
return true // 如果这里是return false,那么componentWillUpdate,componentDidUpdate,render函数,都不会执行
}
componentWillUpdate(nextProps, nextState) {
console.log("组件将要被更新")
console.log(nextProps, nextState)
}
componentDidUpdate(prevProps, prevState) {
console.log("组件更新完成")
console.log(prevProps, prevState)
}
}
控制台
是否更新组件
{} {msg: 222}
组件将要被更新
{} {msg: 222}
组件渲染
组件更新完成
{} {msg: 111}
可以看到,shouComponentUpdate和componentWillUpdate的两个参数,都是更新前的值,而componentDidUpdate的两个参数,都是更新后的值
componentWillReceiveProps和componentWillUnmount
先说说componentWillUnmount,也就是组件被销毁的时候触发。如
// 父组件
import ChildrenTest from "./childrenTest"
export default class App extends Component {
constructor() {
super()
this.state = {
isShowChildrenTest: true
}
}
handleUnmount = () => {
this.setState({
isShowChildrenTest: false
})
}
render() {
return (
<div>
{this.state.isShowChildrenTest ? <ChildrenTest></ChildrenTest> : ""}
<button onClick={this.handleUnmount}>销毁组件</button>
</div>
)
}
}
//子组件
export default class childrenTest extends Component {
render() {
return (
<div>childrenTest</div>
)
}
componentWillUnmount() {
console.log("我被销毁了")
}
}
当点击父组件的“销毁组件”按钮的时候,变量isShowChildrenTest变成了false,那么子组件就被销毁了,此时子组件的componentWillUnmount就触发了
我们再来看看 componentWillReceiveProps,组件从父组件接收参数,且父组件的render函数重新执行的时候,这个函数会执行。(如果这个组件是第一次存在于父组件中,不会执行,如果这个组件之前就存在于父组件中,会执行。),他接收一个参数nextProps,是不是很熟悉,因为他跟shouldComponentUpdate的参数nextProps是一样的,是改变后的props。
我们可以把父组件传递过来的props赋值给子组件本身的state,因为react是不允许子组件去修改父组件的值,但是可以修改自身的state。
//父组件
export default class App extends Component {
constructor() {
super()
this.state = {
faMsg: "父组件的msg"
}
}
handleChangeFaMsg = () => {
this.setState({
faMsg: "父组件的msg的值改变了"
})
}
render() {
return (
<div>
<ChildrenTest faMsg={this.state.faMsg}></ChildrenTest>
<button onClick={this.handleChangeFaMsg}>修改父组件的值</button>
</div>
)
}
}
//子组件
export default class childrenTest extends Component {
constructor(props) {
super(props)
this.state = {
faMsg: ""
}
}
render() {
return (
<div>{this.props.faMsg}</div>
)
}
componentWillReceiveProps(nextProps) {
console.log(nextProps)
this.setState({
faMsg: nextProps.faMsg
})
}
}
当父组件传递给子组件的props发生改变的时候,我们对应的也同步修改state的值。
然后在子组件中,我们就可以操作这个父组件传递过来的值了(不过不建议这样做,因为为了保证数据一致性,不应该在子组件中修改父组件传递过来的值,如果想要修改,应该在子组件中去调用父组件的某个方法去修改父组件的值)
componentWillUnmount:
会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除定时器,取消网络请求或清除在 componentDidMount() 中创建的订阅,清理无效的DOM元素等垃圾清理工作。
到这里就结束辣,在最新的react版本中,类似于componentWillMount之类的函数,已经慢慢的被废除了,需要了解的小伙伴们,可以自行上react的官网查阅。