React组件的生命周期深入理解分析

 更新时间:2022年12月01日 09:41:09   作者:花铛  
组件的生命周期就是React的工作过程,就好比人有生老病死,自然界有日月更替,每个组件在网页中也会有被创建、更新和删除,如同有生命的机体一样

组件从创建到销毁的过程,被称为组件的生命周期。

在生命周期的各个阶段都有相对应的钩子函数,会在特定的时机被调用,被称为组件的生命周期钩子。

生命周期回调函数 = 生命周期钩子函数 = 生命周期函数 = 生命周期钩子

函数式组件没有生命周期,因为生命周期函数是 React.Component 类的方法实现的,函数式组件没有继承 React.Component,所以也就没有生命周期。

<-- 容器!-->
<div id="test"></div>
// 创建组件
class Life extends React.Component{
	state = {opacity:1}
	// 调用时机:组件挂载完毕
	componentDidMount(){
		this.timer = setInterval(() => {
			let {opacity} = this.state
			opacity -= 0.1
			if(opacity <= 0) opacity = 1
			this.setState({opacity})
		}, 200);
	}
	//调用时机:组件将要卸载
	componentWillUnmount(){
		clearInterval(this.timer)
	}
	handleUnmount = ()=>{
		//卸载组件
		ReactDOM.unmountComponentAtNode(document.getElementById('test'))
	}
	//调用时机:初始化渲染、状态更新之后
	render(){
		return(
			<div>
				<h2 style={{opacity:this.state.opacity}}>我是一段透明度会变化的文字</h2>
				<button onClick={this.handleUnmount}>点击卸载</button>
			</div>
		)
	}
}
//渲染组件
ReactDOM.render(<Life/>,document.getElementById('test'))

生命周期钩子(新)

新的生命周期钩子增加了 getDerivedStateFromProps 和 getSnapshotBeforeUpdate。

constructor():constructor() 构造函数在 React 组件挂载之前被调用。

如果不初始化 state 或不为事件处理函数绑定实例,则不需要写 constructor()。

不能在 constructor() 构造函数内部调用 this.setState(), 因为此时第一次 render() 还未执行,也就意味 DOM 节点还未挂载。

static getDerivedStateFromProps(nextProps, prevState):在每次调用 render() 方法之前都会被调用,在初始化和更新时都会被调用。

getDerivedStateFromProps() 第一个参数为即将更新的 props,第二个参数为上一个状态的 state,可以比较 props 和 state 来加一些限制条件,防止无用的 state 更新。

getDerivedStateFromProps() 的返回值是必须的。返回一个对象来更新 state,如果不需要更新,返回 null 即可。 getDerivedStateFromProps() 适用于 state 的值在任何时候都取决于 props 的情况。 getDerivedStateFromProps() 是一个静态函数,是放在组件身上的,而不是放在组件实例身上,因此不能使用 this。

// 之前使用 componentWillReceiveProps
componentWillReceiveProps(nextProps) {
    if (nextProps.location.search !== this.props.location.search) {
    	this.init()
    }
}
// 现在使用 getDerivedStateFromProps:相当于把 componentWillReceiveProps 拆分成 getDerivedStateFromProps 和 componentDidUpdate
static getDerivedStateFromProps(nextProps, prevState) {
  const {search} = nextProps.location
  if (search !== prevState.search) {
    return {
      search,
    }
  }
  return null
}
componentDidUpdate(prevProps, prevState) {
  const {search} = this.state
   if (search !== prevState.search) {
    this.init()
  }
}

render():render() 方法是类组件中唯一必须实现的方法,用于渲染 DOM,render() 方法必须返回 reactDOM。

在 render() 的 return 之前不能写 setState,否则会触发死循环导致内存崩溃;return 体里面是可以写的。

// Wrong
render(){
	this.setState({...})
	return (...)
}
// Correct
render(){
	return (
		<input onClick={()=>this.setState({...})} />
   )
}

componentDidMount():在组件挂载后 (插入 DOM 树后) 立即调用,此生命周期是发送网络请求、开启定时器、订阅消息等的好时机,并且可以在此钩子函数里直接调用 setState()。

shouldComponentUpdate(nextProps, nextState):在组件更新之前调用,可以控制组件是否进行更新, 返回 true 时组件更新, 返回 false 则不更新。不写此生命周期钩子时默认为 true。

shouldComponentUpdate() 第一个参数是即将更新的 props 值,第二个参数是即将更新后的 state 值,可以根据更新前后的 props 或 state 来比较加一些限制条件,决定是否更新,进行性能优化。

不要在 shouldComponentUpdate 中调用 setState(),否则会导致无限循环调用更新、渲染,直至浏览器内存崩溃。

getSnapshotBeforeUpdate(prevProps, prevState):在最新的渲染数据提交给 DOM 前会调用,也就是说,在 render 之后,在 componentDidUpdate 之前调用。使得组件可以在更新之前获取快照值。不常用。

它可以使组件在 DOM 真正更新之前捕获一些信息(例如滚动位置),此生命周期返回的任何值都会作为参数传递给 componentDidUpdate(),如不需要传递任何值,那么返回 null。返回值是必须的。

componentDidUpdate(prevProps, prevState, snapshot):componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行。

包含三个参数,第一个是上一次props值。 第二个是上一次state值,第三个是“snapshot” 参数传递。

可以进行前后 props 的比较进行条件语句的限制,来进行 setState() , 否则会导致死循环。

componentWillUnmount():componentWillUnmount() 在组件即将被卸载或销毁时进行调用。此生命周期是清理定时器、取消订阅等操作的好时机。

组件的挂载流程:

  • constructor
  • getDerivedStateFromProps
  • render
  • componentDidMount

setState 更新流程:

  • getDerivedStateFromProps
  • shouldComponentUpdate
  • render
  • getSnapshotBeforeUpdate
  • componentDidUpdate

组件的卸载流程: componentWillUnmount

生命周期钩子(旧)

React 从 v16.3 开始废弃 componentWillMount、componentWillReceiveProps、componentWillUpdate 三个钩子函数。在新版本中使用需要加上 UNSAFE_ 前缀,否则会触发控制台的警告。

UNSAFE 不是指安全性,而是表示使用这些生命周期的代码在 React 的未来版本中更有可能出现 Bug,尤其是在启用异步渲染之后。

组件的挂载流程:

  • constructor
  • componentWillMount
  • render
  • componentDidMount

setState 更新流程:

  • shouldComponentUpdate
  • componentWillUpdate(组件更新之前调用)
  • render
  • componentDidUpdate

forceUpdate 强制更新流程:

  • componentWillUpdate(组件更新之前调用)
  • render
  • componentDidUpdate

父组件 render 之后子组件的更新流程:

  • componentWillReceiveProps(子组件接收到新的 props 之前调用,第一次接收到 props 不会调用)
componentWillReceiveProps(nextProps) {
	// 可以和 this.props 中的数据进行对比,以决定是否要执行某些方法
}
  • shouldComponentUpdate
  • componentWillUpdate(组件更新之前调用)
  • render
  • componentDidUpdate

组件的卸载流程:

componentWillUnmount

父子组件生命周期

当子组件自身的 state 状态改变,不会对父组件产生副作用的情况下,父组件不会进行更新,也就是不会触发父组件的生命周期。

当父组件状态变化时(不会是否更改到传给子组件的 props),会触发自身和子组件对应的生命周期。

render 以及 render 之前的生命周期,父组件先执行;

render 之后的生命周期,子组件先执行,并且是与父组件交替执行。

父子组件初始化流程:

  • 父组件constructor
  • 父组件getDerivedStateFromProps
  • 父组件render
  • 子组件constructor
  • 子组件getDerivedStateFromProps
  • 子组件render
  • 子组件componentDidMount
  • 父组件componentDidMount

子组件修改自身的 state 状态流程:

  • 子组件getDerivedStateFromProps
  • 子组件shouldComponentUpdate
  • 子组件render
  • 子组件getSnapshotBeforeUpdate
  • 子组件componentDidUpdate

父组件修改 state 状态流程:

  • 父组件getDerivedStateFromProps
  • 父组件shouldComponentUpdate
  • 父组件render
  • 子组件getDerivedStateFromProps
  • 子组件shouldComponentUpdate
  • 子组件render
  • 子组件getSnapshotBeforeUpdate
  • 父组件getSnapshotBeforeUpdate
  • 子组件componentDidUpdate
  • 父组件componentDidUpdate

父组件卸载子组件:

// 通过点击父组件中的 [卸载 / 挂载子组件] 按钮来卸载子组件
handelToggle = () => {
    this.setState({
      isHidden: !this.state.isHidden
    })
  }
<button onClick={this.handelToggle}>挂载/卸载子组件</button>
{this.state.isHidden ? '' : <Child />>}
  • 父组件getDerivedStateFromProps
  • 父组件shouldComponentUpdate
  • 父组件render
  • 父组件getSnapshotBeforeUpdate
  • 子组件componentWillUnmount
  • 组件componentDidUpdate

父组件重新挂载子组件:

再次点击父组件中的 [卸载 / 挂载子组件] 按钮来挂载子组件。

  • 父组件getDerivedStateFromProps
  • 父组件shouldComponentUpdate
  • 父组件render
  • 子组件constructor
  • 子组件getDerivedStateFromProps
  • 子组件render
  • 父组件getSnapshotBeforeUpdate
  • 子组件componentDidMount
  • 父组件componentDidUpdate

到此这篇关于React组件的生命周期深入理解分析的文章就介绍到这了,更多相关React组件的生命周期内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用React实现虚拟列表的示例代码

    利用React实现虚拟列表的示例代码

    虚拟列表,其实就是将一个原本需要全部列表项的渲染的长列表,改为只渲染可视区域内的列表项,但滚动效果还是要和渲染所有列表项的长列表一样。本文就将利用React实现虚拟列表,需要的可以参考一下
    2022-08-08
  • React Router v4 入坑指南(小结)

    React Router v4 入坑指南(小结)

    这篇文章主要介绍了React Router v4 入坑指南(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • React中memo useCallback useMemo方法作用及使用场景

    React中memo useCallback useMemo方法作用及使用场景

    这篇文章主要为大家介绍了React中三个hooks方法memo useCallback useMemo的作用及使用场景示例,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2023-03-03
  • react-dnd实现任意拖动与互换位置

    react-dnd实现任意拖动与互换位置

    这篇文章主要为大家详细介绍了react-dnd实现任意拖动与互换位置,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • React Native 脚手架的基本使用详解

    React Native 脚手架的基本使用详解

    这篇文章主要介绍了React Native 脚手架的基本使用详解,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-04-04
  • react入门级详细笔记

    react入门级详细笔记

    这篇文章讲述了React的基本介绍,基本使用和React相关js库.通过这篇文章可以入门React的使用,可以快速上手使用React进行代码的编写
    2021-06-06
  • react-router v6实现动态路由实例

    react-router v6实现动态路由实例

    这篇文章主要为大家介绍了react-router v6实现动态路由实例详解,<BR>有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 浅析JS中什么是自定义react数据验证组件

    浅析JS中什么是自定义react数据验证组件

    我们在做前端表单提交时,经常会遇到要对表单中的数据进行校验的问题。这篇文章主要介绍了js中什么是自定义react数据验证组件,需要的朋友可以参考下
    2018-10-10
  • 详解React中key的作用

    详解React中key的作用

    这篇文章主要介绍了React中key的作用,帮助大家更好的理解和学习使用React,感兴趣的朋友可以了解下
    2021-04-04
  • 深入学习TypeScript 、React、 Redux和Ant-Design的最佳实践

    深入学习TypeScript 、React、 Redux和Ant-Design的最佳实践

    这篇文章主要介绍了深入学习TypeScript 、React、 Redux和Ant-Design的最佳实践,TypeScript 增加了代码的可读性和可维护性,拥有活跃的社区,,需要的朋友可以参考下
    2019-06-06

最新评论