React之生命周期
旧版本,函数组件是没有生命周期的。新版本中通过useEffect触发函数的生命周期
一、基于类组件的生命周期
React的组件生命周期分为
挂载阶段
、更新阶段
和销毁阶段
。因为React的state不具有Vue的响应式,所以并没有create阶段
1、挂载阶段: 【组件被创建并插入到DOM中的过程】
-
constructor:组件被创建时调用,用于初始化状态和绑定方法。
-
static getDerivedStateFromProps:在组件被创建和重新渲染之前调用,用于根据props更新状态。
-
【已废弃】componentWillMount: 组件即将挂载,已经被废弃,向下兼容请使用【UNSAFE_componentWillMount】
- 执行1次
- 特点:可以访问state、不能操作DOM
-
render: 对组件视图结构进行编译【必须定义的一个钩子】
- 先默认执行1次,后去每次setState都会执行一次
- 特点:可以访问state、不能操作DOM
-
componentDidMount: 组件挂载完成
- 执行一次
- 特点: 可以访问state,也能操作DOM
- 应用场景:发送请求;初始化第三方插件
import { Component } from 'react'export default class Home extends Component {state = {title: 'home'}clickUpdate = () => {this.setState({title: '主页'})}UNSAFE_componentWillMount(): void {console.log(this.state.title) // 'title'console.log(document.querySelector('.home_box')) // null}render() {console.log(this.state.title, 'render') // 'title'console.log(document.querySelector('.home_box'), 'render') // nullreturn (<><div className="home_box">{this.state.title}</div><button onClick={this.clickUpdate}>获取DOM</button></>)}componentDidMount(): void {console.log(this.state.title) // 'title'console.log(document.querySelector('.home_box')) // <div class="home_box">home</div>}
}
2、更新阶段【组件的props或state发生变化时的过程】
- static getDerivedStateFromProps(props,state):在组件被重新渲染之前调用,用于根据props更新状态。[替代了componentWillReceiveProps]
- shouldComponentUpdate: 是否要执行组件更新。如果显示的声明了该钩子,则必须返回一个布尔值,true:执行组件更新;false:不执行组件更新。如果没有显示的声明该钩子,则正常执行组件更新
- 应用场景: 手动进行性能优化
- 触发条件:state状态数据发生改变
- 系统参数:nextProps: 更新后的props; nextState:更新后的state
- 特点: 还没有完成数据和视图的更新
- 【已废弃】componentWillUpdate: 即将执行组件更新: *已经被废弃,向下兼容请使用【UNSAFE_componentWillUpdate】
- 触发条件:state状态数据发生改变
- 系统参数:nextProps: 更新后的props; nextState:更新后的state
- 特点: 还没有完成数据和视图的更新
- render: 重新执行视图编译
- 触发条件:state状态数据发生改变
- 特点: 完成数据更新, 但是还没有完成视图更新
- getSnapshotBeforeUpdate:在组件被重新渲染之前调用,用于获取更新前的DOM状态。[替换componetnWillUpdate]
- componentDidUpdate:组件更新完成
- 触发条件:state状态数据发生改变
- 特点:已经完成数据和视图的更新
- 系统参数:prevProps: 更新之前的props; prevState:更新之前的state【此时this.state是更新后的state】
- 场景: 进行DOM操作、网络请求等副作用操作。
- componentWillReceiveProps:组件接收的外部props属性数据发生改变的时候执行: *已经被废弃,向下兼容请使用【UNSAFE_componentWillReceiveProps】
- 触发条件:props数据发生改变
- 特点:已经完成数据和视图的更新
import { Component } from 'react'export default class Home extends Component {state = {title: 'home'}clickUpdate = () => {this.setState({title: '主页'})}UNSAFE_componentWillMount(): void {console.log(this.state.title) // 'title'console.log(document.querySelector('.home_box')) // null}render() {console.log(this.state.title, 'render') // 'title'console.log(document.querySelector('.home_box'), 'render') // nullreturn (<><div className="home_box">{this.state.title}</div><button onClick={this.clickUpdate}>获取DOM</button></>)}componentDidMount(): void {console.log(this.state.title) // 'title'console.log(document.querySelector('.home_box')) // <div class="home_box">home</div>}// 更新阶段shouldComponentUpdate(nextProps: Readonly<{}>,nextState: Readonly<{ title: string }>,nextContext: any): boolean {// nextProps: {}, nextState: 更新后的state, nextContext: {}console.log(nextProps, nextState, nextContext)if (this.state.title === nextState.title) {// 如果数据没有发生变化 则不执行组件更新, 即是不执行render()钩子return false}return true}// componentWillUpdate: 严格模式下eslint, 会报错// UNSAFE_componentWillUpdate: 这个在高版本React也废弃了, 但是在ESLint模式下也可以使用[向下兼容]UNSAFE_componentWillUpdate(nextProps: Readonly<{}>,nextState: Readonly<{}>,nextContext: any): void {console.log(nextProps, nextState, nextContext, 'UNSAFE_componentWillUpdate')}componentDidUpdate(prevProps: Readonly<{}>,prevState: Readonly<{}>,snapshot?: any): void {console.log(prevProps, prevState, snapshot, 'componentDidUpdate')}UNSAFE_componentWillReceiveProps(nextProps: Readonly<{}>,nextContext: any): void {console.log(nextProps, nextContext, 'UNSAFE_componentWillReceiveProps')}
}
3、销毁阶段: 【组件从DOM中移除的过程】
- componentWillUnmount:组件被移除前调用,可以进行清理操作,如取消定时器、取消订阅等。
4、补充
除了上述方法,还有一些其他的生命周期方法,如错误处理相关的方法(componentDidCatch、getDerivedStateFromError)和静态方法(getDerivedStateFromProps、getDerivedStateFromError)
需要注意的是,React 16.3之后,一些生命周期方法已经被废弃或改名,如componentWillMount、componentWillUpdate、componentWillReceiveProps等,建议使用新的方法来替代
- 旧版生命周期图
- 新版生命周期图
二、函数组件的生命周期
React 18引入了一些新的生命周期方法,以便更好地管理组件的生命周期事件
useEffect
: 【异步执行的,不会阻塞渲染】用于在组件挂载、更新或卸载时执行副作用操作。它可以替代旧的生命周期方法componentDidMount、componentDidUpdate和componentWillUnmount
import { useState, useEffect } from 'react'const Home = () => {const [count, setCount] = useState(0)const add = () => {setCount(count + 1)}// 接收一个参数时:组件加载完成和组件状态更新时 执行useEffect(function () {console.log('zhw')})// 如果只希望函数挂载完后,执行一次,组件状态变化不再执行,可以传空数组useEffect(function () {console.log('zhw')}, [])// 接收参数二时,参数二是一个数组,用于指定依赖数据,用于当依赖数据变化时,执行一次回调// 1、组件挂载完后执行一次;2、仅仅当count的状态更新,执行一次useEffect(function () {console.log('zhw')}, [count])// 组件卸载之前按// 1、useEffect(function () {return function () {// 该子函数会在组件 即将卸载 和 状态更新 的时候,自动执行console.log('组件卸载了')}}) // 2、useEffect(function () {return function () {// 该子函数会在组件 仅仅在 即将卸载 的时候,自动执行console.log('组件卸载了')}}, []) return (<><span>{count}</span><button onClick={add}>+</button></>)
}
export default Home
useLayoutEffect
: 在DOM更新之后同步执行[阻塞渲染],以确保在浏览器绘制之前执行副作用操作。
适用于需要在浏览器执行绘制和布局之前立即执行的副作用操作。
import { useLayoutEffect, useState } from 'react'const Home = () => {const [count, setCount] = useState(0)const add = () => {setCount(count + 1)}useLayoutEffect(function () {console.log('useLayoutEffect')},[count])return (<><span>{count}</span><button onClick={add}>+</button></>)
}
export default Home