❤React-组件的新旧生命周期

1、组件的生命周期概述.

👉生命周期含义:

从组件出生到更新、改变、销毁(创建\更新\销毁)的整个阶段。

👉生命周期的钩子函数含义:

组件的每个阶段都伴随着一些方法,就是生命周期的钩子函数,我们就是通过控制这些生命周期函数从而控制组件。

👉生命周期意义:

组件的生命周期有助于理解组件的运行方式、完成更复杂的组件功能、分析组件错误原因

👉TIPS

只有类组件才有生命周期

2、 组件生命周期的三个阶段

1.每个阶段的执行时机

2、每个阶段钩子函数的执行顺序

3、每个阶段钩子函数的作用

👉主要阶段

组件的生命周期主要分为三个主要阶段:

挂载(Mounting)、

更新(Updating)、

卸载(Unmounting)

生命周期图❤React-组件的新旧生命周期_钩子函数

👉 创建时
  1. 创建时(挂载阶段)
执行时机:组件创建时(页面加载时)
  • 1.

执行顺序:❤React-组件的新旧生命周期_初始化_02

👉钩子函数
钩子函数触发时机作用
constructor创建组件时,最先执行1. 初始化 state
2. 为事件处理程序绑定 this
render每次组件渲染都会触发1. 渲染 UI(注意:不能调用 setState())
componentDidMount组件挂载(完成 DOM 渲染)后1. 发送网络请求
2. DOM 操作
👉使用示例
class MyComponent extends React.Component {constructor(props) {super(props);// 初始化 statethis.state = {count: 0};// 处理 this 指向问题console.warn('生命周期钩子函数:constructor');}// 1. 进行 DOM 操作// 2. 发送 ajax 请求,获取远程数据componentDidMount() {console.warn('生命周期钩子函数:componentDidMount');// 这里可以进行 AJAX 请求等操作// const title = document.getElementById('title');// console.log(title);}render() {// 错误演示!!!不要在 render 中调用 setState// this.setState({ count: 1 });  // **错误**:不要在 render 中调用 setState!console.warn('生命周期钩子函数:render');return (<div>Count: {this.state.count}<button onClick={() => this.setState({ count: this.state.count + 1 })}>Increment</button></div>);}
}export default MyComponent;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
👉更新时
更新的三种情况
- **执行时机**1. `setState()`2. `forceUpdate()`3. 组件接收到新的 `props`
  • 1.
  • 2.
  • 3.
  • 4.
  • 说明:以上三者任意一种变化,组件就会重新渲染。
执行顺序
钩子函数触发时机作用
render()每次组件渲染都会触发渲染 UI(与挂载阶段是同一个 render)
componentDidUpdate()组件更新(完成 DOM 渲染)后1. 发送网络请求
2. DOM 操作
注意:如果要 setState(),必须放在一个 if 条件中
👉使用示例
class Counter extends React.Component {render() {console.warn('--子组件--生命周期钩子函数:render');return (统计豆豆被打的次数: {this.props.count});}componentDidUpdate(prevProps) {console.warn('--子组件--生命周期钩子函数:componentDidUpdate');// 正确做法:在条件中调用 setStateif (prevProps.count !== this.props.count) {// 可以在这里调用 setState,但需要确保不会导致无限循环// this.setState({});}// 错误演示!!!// 直接调用 setState 会导致递归更新// this.setState({});// 获取 DOMconst title = document.getElementById('title');console.log(title.innerHTML);}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
componentDidUpdate(prevProps) {console.warn('--子组件--生命周期钩子函数:componentDidUpdate');// 比较更新前后的 props 是否相同,决定是否重新渲染组件console.log('上一次的props:', prevProps, ', 当前的props:', this.props);// 如果 count 发生变化,更新状态if (prevProps.count !== this.props.count) {this.setState({ count: 0 });  // 假设你想将 count 状态重置为 0}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
组件的函数周期

render 生命周期渲染 componenetDidUpdate() 生命周期更新

注意部分:

seState 应该放在判断if 里面ajax的请求部分应该放在这里

class Counter extends React.Component {render() {console.warn('--子组件--生命周期钩子函数:render');return 统计豆豆被打的次数: {this.props.count};}componentDidUpdate() {console.warn('--子组件--生命周期钩子函数:componentDidUpdate');// 获取 DOM 元素const title = document.getElementById('title');console.log(title.innerHTML); // 打印 h1 元素的内容}
}export default Counter;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
👉组件卸载时(卸载阶段)

执行时间:组件从页面之中消失时

钩子函数触发时机作用
componentWillUnmount组件卸载(从页面中消失)执行清理工作(比如:清理定时器等)
  • componentDidMount(){}组件的挂载阶段
  • componentWillUnmount(){}组件的卸载阶段

组件的挂载阶段执行的一些方法可以在组件的卸载阶段除去

class Counter extends React.Component {componentDidMount() {// 开启定时器this.timerId = setInterval(() => {console.log('定时器正在执行~');}, 500);}render() {return 统计豆豆被打的次数: {this.props.count};}componentWillUnmount() {console.warn('生命周期钩子函数: componentWillUnmount');// 清理定时器clearInterval(this.timerId);}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

3、旧版本-生命周期钩子函数(react 15 可直接跳过)

❤React-组件的新旧生命周期_初始化_03

我们可以来看看React15 的生命周期函数

(1)constructor() : ES6 类中的构造函数,初始化使用(比如初始化组件状态(state)绑定事件处理器;),组件实例化时调用

(2) componentWillReceiveProps(): 一般使用都是传值 componentWillReceiveProps(nextProps)

  • 已废弃:这个生命周期函数就是在组件即将接收新的属性时被调用(旧版本React中就是更新用)。可以在这里比较新旧属性,然后更新组件的状态;

(3)shouldComponentUpdate(nextProps, nextState): 组件接收到新的属性或者状态时,在更新组件之前调用 shouldComponentUpdate() 函数。

根据新的属性和状态判断是否需要重新渲染组件(性能优化常用)

(4)componentWillMount():

  • 已废弃:新版本不再推荐使用。 在组件即将被挂载到 DOM 中时被调用,很多时候我们可以使用 constructor() 或者 componentDidMount() 来替代。

(5)componentWillUpdate(nextProps, nextState): 已废弃:新版本不再推荐,在组件即将被更新之前被调用,我们可以在组件即将更新之前控制组件。

(6)componentDidUpdate(): 组件第一次被渲染到 DOM 中之后被调用。我们可以进行一些初始化的操作,获取远程数据、订阅事件等

(7)render(): render() 最重要 的生命周期函数之一,返回虚拟 DOM 元素,渲染组件外观和结构.

(8)componentWillUnmount(): 在组件即将被销毁和从 DOM 中移除之前被调用,就类似砸门在vue销毁之前一样,可以取消订阅、清除定时器。

4、重要- 新版本-生命周期钩子函数(react 16 )

(1) constructor

在类组件创建实例时调用,初始化的时候执行一次,可以在组件进行初始化时候控制组件。

不定义 constructor,React 会自动为组件创建一个默认的 constructor

我们来写一个简单的类组件 看看

import React from 'react';
// 生命周期
class Demo extends React.Component {constructor(props: any) {super(props); //super作用 : 传递props,才能在接下来的上下文中,获取到propsconsole.log('constructor-生命周期');}render() {return (<div className="App" id='link'>constructor</div>);}
}
export default Demo;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
constructor-生命周期
  • 1.

作用

-   初始化 state ,获取路由中的参数,组件传值赋值给 state等 。
-   绑定类组件事件,绑定 this 、节流,防抖。
-   对类组件进行生命周期的劫持,渲染劫持等。
  • 1.
  • 2.
  • 3.
import React from 'react';// 01  初始化状态
class Demo extends React.Component {constructor(props: any) {super(props);console.log(props,'props');console.log('constructor-生命周期');//初始化状态this.state={ name:'alien',count: 0,}
}
export default Demo;// 02 **绑定事件处理器**
class MyComponent extends React.Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this);}handleClick(name: string) {console.log(name,'name');return () => {console.log('handleClick');}}
}03 **初始化引用**
constructor(props) { super(props); this.myRef = React.createRef(); 
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
(2) getDerivedStateFromProps (react 16 新增)
getDerivedStateFromProps(nextProps,prevState)
// nextProps 父组件新传递的 props ;
// prevState 组件在此次更新前的 state
  • 1.
  • 2.
  • 3.
  • 4.

组件更新执行包括(props变化,setState、forceUpdate)

注意点

getDerivedStateFromProps 被定义为 static 方法 —— static 方法内部拿不到组件实例的 this

任何操作 this.fetch()之类的都不可以在里卖面使用

在组件的操作之中大致归为两类

  • 基于 props 更新状态
class MyComponent extends React.Component {constructor(props) {super(props);this.state = {value: ''};}static getDerivedStateFromProps(nextProps, prevState) {// 如果接收到新的值,更新状态if (nextProps.value !== prevState.value) {return {value: nextProps.value};}return null; // 不更新状态}// ...
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 控制内部状态
class MyComponent extends React.Component {constructor(props) {super(props);this.state = {isFocused: false};}static getDerivedStateFromProps(nextProps, prevState) {if (nextProps.autoFocus && !prevState.isFocused) {return {isFocused: true};}return null;}// ...
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
(3 )render

渲染时操作元素

(4)componentDidMount
componentDidMount(){}
组件挂载到 DOM 后立即被调用,跟上面作用一样,进行数据获取、订阅事件等初始化工作
  • 1.
  • 2.
(5)shouldComponentUpdate

就是判断是否需要重新渲染组件,主要依赖传入的props 或 state 来决定是否更新组件

shouldComponentUpdate(newProps,newState,nextContext){}
// 参数含义 (新的 旧的 更新的)
  • 1.
  • 2.
(6)getSnapshotBeforeUpdate

组件更新 DOM 之前被调用(如滚动位置的使用)

getSnapshotBeforeUpdate(prevProps, prevState) { 
// 返回滚动位置 return this.myRef.current.scrollHeight; // prevProps更新前的props   preState更新前的state;
}
// 参数含义 (新的 旧的 更新的)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

注意点:

  • getSnapshotBeforeUpdate必须与 componentDidUpdate 一起使用,因为它的返回值会作为第三个参数传递给 componentDidUpdate
  • 我们在大多数情况下不使用,它主要用于处理一些处理复杂的 UI 动画或需要手动保存和恢复某些 DOM 状态的情况。
(7)componentDidUpdate

组件更新(re-render)完成之后被调用

componentDidUpdate(prevProps, prevState, snapshot){}
// 更新之前的 props 更新之前的 prevState  更新之前的 DOM 信息   
// 操作可能会触发额外的组件更新,因此需要谨慎处理,以避免陷入无限循环
  • 1.
  • 2.
  • 3.
(8) componentWillUnmount

组件销毁阶段唯一执行的生命周期

componentDidMount 设置定时器,componentWillUnmount清楚定时器

import React from 'react';// 生命周期
class Demo extends React.Component {constructor(props) {super(props);console.log(props,'props');console.log('constructor-生命周期');//初始化状态this.state={ count: 0,}}componentDidMount(){console.log('componentDidMount');this.interval = setInterval(() => {this.setState({ count: this.state.count + 1 });}, 1000);}componentWillUnmount() {console.log('componentWillUnmount');clearInterval(this.interval);}render() {return (<><p>Timer: {this.state.count}</p></>);}
}
export default Demo;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

输出结果:

48 alien
  • 1.

刷新以后组件重新销毁创建定时器

6、(函数式组件)React声明周期函数

需要注意的是:

React函数式组件中,没有像类组件那样明确的声明周期函数,可以通过 React Hooks实现类似的生命周期函数

常用的 React Hooks 及其对应的生命周期函数

1.  `useState`: 用于声明状态变量,类似于类组件中的 `state`
1.  `useEffect`: 在组件渲染后执行副作用操作,类似于类组件中的 `componentDidMount`, `componentDidUpdate`, `componentWillUnmount`
1.  `useContext`: 用于访问 React 的上下文,类似于类组件中的 `static contextType``Context.Consumer`
1.  `useReducer`: 用于应对复杂的状态管理逻辑,类似于类组件中的 `setState`
1.  `useRef`: 创建一个可变的 ref 对象,类似于类组件中的 `createRef`
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

Hooks 都可以帮助我们在函数式组件中实现类似于类组件的生命周期函数的功能