玩转Reactjs第四篇-组件(生命周期)

2024-03-20 10:18

本文主要是介绍玩转Reactjs第四篇-组件(生命周期),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、前言

     前一篇主要介绍了Reactjs组件的创建模式,了解了state以及props的基本知识和用法。本篇将重点介绍下Reactjs的生命周期这对于我们认识Reactjs的实现原理,正确使用钩子函数至关重要。

   Reactjs在V16.3版本之前使用的是旧版本的生命周期,之后启用了新版的生命周期,V17版本将彻底废弃旧版本。我们将两个版本都介绍下。

二、旧版本

     Reactjs生命周期包括挂载时(Mounting),更新时(Updateing),卸载时(Unmounting)三种场景,每种场景在不同状态提供相关的钩子函数,我们可以使用这些钩子函数,实现自定义功能。

生命周期钩子函数时序的示意图如下:

1、挂载时(Mounting)

Reactjs组件首次加载时执行的流程,constructor->componentWillMount->render->componentDidMount。

  • constructor

调用时机:组件挂载前会调用构造函数。

钩子作用:前一篇我们也讲到,在构造方法里,主要做以下两件事:

(1)初始化state,这里是唯一一个可以使用this.state进行初始化的地方,其他的地方只能使用setState更新。

(2)组件内定义的方法绑定实例,前一篇也讲到如果不用箭头函数定义方法,必须在构造器中绑定this。

如果不需要使用以上两点,可以不定义组件的构造函数。

函数示例:示例如下:

constructor(props){// 1、调用父类构造方法super(props);//2、初始化state对象this.state = {hotItem:['口罩','手套','酒精',]};//绑定thisthis.changeHot = this.changeHot.bind(this);
}
  • componentWillMount(即将废弃)

在方法即将废弃,可以使用到React 17版本,但是会和新的组件生命周期钩子函数冲突,建议不要使用。

调用时机:在调用render()前调用。

钩子作用:在该方法里面调用setState不会触发额外的渲染,所以想要在该方法中请求外部数据,减少一次render,是一个常见的误区,总的来说该方法没有太大的作用。

  • render

调用时机:首次挂载以及更新时,都会调用该方法进行渲染。

钩子作用:render方法是class组件中唯一需要实现的方法。在该钩子方法里,将React JSX渲染成DOM节点,并挂载到DOM树中。

render函数应该是纯的,意味着不应该改变组件的状态,其每次调用都应返回相同的结果,同时它不会直接和浏览器交互。

函数示例:该方法的实现形式,前一篇我们也重点介绍了,如App.js中,实例如下:

render(){return (<div className="App">{/* 引入组件 */}<SearchBox changeSearchVal = {this.changeSearchVal}/><SearchHot /><SearchList searchListVal={this.state.searchListVal}><div>为您搜索到2条记录</div></SearchList></div>);}
  • componentDidMount

调用时机:执行完render函数(DOM节点已创建完成并挂载到DOM数中(节点插入DOM数)),立即执行。

钩子作用:在componentDidMount中可以进行以下的操作:

(1)请求网络数据,并调用setState进行更新,它将会触发一次额外的渲染,但是它将在浏览器刷新屏幕之前发生。这保证了在此情况下即使render()将会调用两次,用户也不会看到中间状态

(2)通过ref获取DOM的节点,获取DOM属性或者操作DOM。

函数示例:在App.js中,我们增加componentDidMount方法,在该钩子函数中获取默认的搜索列表,这样就能实现在首次加载完成后,页面展示默认列表。

componentDidMount(){console.log("App componentDidMount");fetch("http://localhost:3000/search.json",{method:'GET',}).then(response => response.json()).then((data)=>{this.setState({searchListVal:data.search});})}

2、更新时(Updateing)

挂载完成后,当传入父组件的props,以及组件内的state值发生变化,会触发更新时流程。componentWillReceiveProps->shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate

  • componentWillReceiveProps(nextProps)(即将废弃)

该钩子函数将在React 17版本废弃。

调用时机:在已挂载的组件接收新的 props 之前被调用。

钩子作用:当接收到新属性后,通过if比较新旧Props不同,此方法中使用 this.setState() 执行 state 转换。这个和新版本的getDerivedStateFromProps作用类似。

  • shouldComponentUpdate(nextProps,nextState)

调用时机:props或者state发送变化后,render调用前调用该钩子函数。父组件更新prop,或者调用setState都会触发。但是首次挂载以及forceUpdate不会触发该方法。

钩子作用:该函数可以决定是否继续渲染(是否执行render方法),入参为新的props和state,返回的是个布尔值,true表示继续渲染,false则表示阻止渲染,默认返回true。

     在Vue中,通过监听相关属性值的变化,通过机制自动判断是否需要渲染,无法"人为"干预。在Reactjs中,利用shouldComponentUpdate为我们提供了干预的契机,进行精确控制。

适用场景:在某些状态或属性变化时,通过this.props和nextProps以及this.state 和 nextState比较,来判断是否需要重新渲染该组件。

函数示例:我们来改写下SearchHot.js,当热搜的个数有变化时,返回false,不继续渲染。

shouldComponentUpdate(nextProps,nextState){console.log(nextState.hotItem.length);if(this.state.hotItem.length != nextState.hotItem.length){return false;}return true;}

由于state.hotItem新旧值的长度不一致,所以点击"下一批",页面不会有变化。

需要注意的是,state和props需要保持结构简单,层次不要太深,不建议在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能。

如果仅做浅层次比较,可以考虑使用React.PureComponent。

  • componentWillUpdate(nextProps, nextState)(即将废弃)

该钩子函数将在React 17版本废弃,

调用时机:当组件收到新的 props 或 state 时,会在渲染之前调用。

钩子作用:入参为新的props以及state,使用此作为在更新发生之前执行准备更新的机会,初始渲染不会调用此方法。

适用场景:可以读取DOM属性,为componentDidUpdate作准备(使用场景少)。不能在此方法中调用 this.setState()

  • componentDidUpdate(prevProps, prevState, snapshot)

调用时机:在组件已经重新渲染之后调用,首次渲染不会执行此方法。

钩子作用:入参为前props,state值,第三个参数与新版本getSnapshotBeforeUpdate有关,下一节介绍。其作用类似componentDidMount,此时已经挂载完成,可以做DOM进行操作,也可以进行网络请求。

使用场景:对DOM进行操作,比如滚动条指定到 位置,获取DOM尺寸等。在该方法里,可以调用setState,但是要包裹在一定的条件中,否则会 引起死循环。调用setSate会引起再一次的渲染,虽然用户看不见(此时浏览器还没有变化),但是会影响性能。

函数示例:   我们改写下 SearchList.js,每次更新完,滚动条指向列表的指定位置。(这里使用了ref获取dom对象,后面会专门介绍)

componentDidUpdate(prevProps, prevState, snapshot){console.log("componentDidUpdate");//列表的滚动条指向60的位置this.searchul.current.scrollTop=60;}
...
render(){...<ul className="u" ref={this.searchul}>
...
}

3、卸载时(Unmounting)

这个阶段是指组件将被删除并从DOM中清除。

  • componentWillUnmount()

调用时机:在组件卸载及销毁之前直接调用。

适用场景:此方法中执行必要的清理操作,例如,清除 timer,取消网络请求。不要在此方法中调用setState,因为该组件永远不会渲染。

三、新版本

V16.3版本启用了新版本生命周期钩子函数,不过此版本还可以兼容老版本的钩子函数,与老版本一样,也分三种场景。

生命周期的钩子函数时序的示意图如下:

与老版本比较,钩子函数发送如下变化:

删除:componentWillMount,componentWillReceiveProps,componentWillUpdate

新增:getDerivedStateFromProps,getSnapshotBeforeUpdate。

其他的函数保留。我们重点介绍下新增的。

  • static getDerivedStateFromProps(nextProps,preState)

调用时机:props以及state发送更新后,会在调用 render 方法之前调用发。与旧的生命周期图比较可以看出,getDerivedStateFromProps处于原来的componentWillMountcomponentWillReceiveProps位置,setState以及forceUpdate方法的调用都会触发该钩子。

钩子作用:从钩子的函数名称可以看出,用接受的props值来改变state值,返回一个新的state。它的入参是新props,旧state,该函数为一个静态的,这就表示无法使用组件实例(无法调用this)。

适用场景:组件分为受控和非受控组件,受控是指数据由父组件的props传入的组件(可以由父组件控制),非受控是指数据保存在内部的state的组件(外部无法直接控制)。如果state可以由props派生出,那么就意味着该组件既是受控的,又是非受控的。其数据源就不唯一了,会导致一些意想不到的问题。通过props派生出state,是我们尽量需要避免的情况

官方文档中,也为我们罗列了以下两种常见场景的替代方案,在你可能不需要使用派生 state这篇博文中进行了详细的介绍。

(1)如果只想在 prop 更改时重新计算某些数据,请使用 memoization helper 代替。
(2)如果你想在 prop 更改时“重置”某些 state,请考虑使组件完全受控或使用 key 使组件完全不受控 代替。

函数示例:SearchList组件中,搜索的结果列表都是由父组件App通过props传给该组件,下面我们修改下,在SearchList定义一个默认列表保存到state中,当父组件传入的prop的列表结果更新后,修改state的值,实现更新。

constructor(props){super(props);this.searchul = React.createRef();//定义默认搜索列表this.state={searchListVal:['电脑','电视','冰箱']};}static getDerivedStateFromProps(nextProps,preState){//当props的列表发送更新,且与state的列表不一致,且不为空if(nextProps.searchListVal!=preState.searchListVal&&nextProps.searchListVal.length > 0){//修改state的searchListVal值,返回新值return{searchListVal:nextProps.searchListVal}}//其他更新,state不变化return null;}
  • getSnapshotBeforeUpdate(prevProps, prevState)

调用时机:在最近一次渲染输出(提交到 DOM 节点)之前调用。

钩子作用:它让你的组件能在当前的值可能要改变前获得它们。这一生命周期返回的任何值将会 作为参数被传递给componentDidUpdate(),即snapshot入参。

适用场景:适用的场景也不常用,它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。

函数示例:在SearchList组件中,我们通过componentDidUpdate,每次加载列表,将滚动条滚动到指定的位置。下面我们再次修改下,获取滚动条之前的位置,在此基础上再累加一个指定值,模拟懒加载的情况下,每次显示最新加载的值(列表底部)。

getSnapshotBeforeUpdate(prevProps, prevState){//获取当前滚动条位置return this.searchul.current.scrollTop;}componentDidUpdate(prevProps, prevState, snapshot){//在滚动条位置上,累加60个if(snapshot!=null){this.searchul.current.scrollTop=snapshot+60;} }

四、与Vue的生命周期比较

这里我们将Reactjs的生命周期与Vue的比较下。

1、挂载时

2、更新时

3、销毁时

五、总结

本章节主要描述了Reactjs的新旧生命周期以及相关钩子函数的调用时机,功能,以及适用场景,并与vue的生命周期做了比较。

老版本的生命周期钩子函数的时序:

1、挂载时,constructor->componentWillMount->render->componentDidMount

2、更新时,componentWillReceiveProps->shouldComponentUpdate->componentWillUpdate->render->componentDidUpdate

3、卸载时,componentWillUnmount

新版本的生命周期钩子函数的时序:

1、挂载时,constructor->getDerivedStateFromProps->render->componentDidMount

2、更新时,getDerivedStateFromProps->shouldComponentUpdate->render->componentDidUpdate

3、卸载时,componentWillUnmount

这篇关于玩转Reactjs第四篇-组件(生命周期)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/829142

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

vue2 组件通信

props + emits props:用于接收父组件传递给子组件的数据。可以定义期望从父组件接收的数据结构和类型。‘子组件不可更改该数据’emits:用于定义组件可以向父组件发出的事件。这允许父组件监听子组件的事件并作出响应。(比如数据更新) props检查属性 属性名类型描述默认值typeFunction指定 prop 应该是什么类型,如 String, Number, Boolean,

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

Maven(插件配置和生命周期的绑定)

1.这篇文章很好,介绍的maven插件的。 2.maven的source插件为例,可以把源代码打成包。 Goals Overview就可以查看该插件下面所有的目标。 这里我们要使用的是source:jar-no-fork。 3.查看source插件的example,然后配置到riil-collect.xml中。  <build>   <plugins>    <pl

火语言RPA流程组件介绍--浏览网页

🚩【组件功能】:浏览器打开指定网址或本地html文件 配置预览 配置说明 网址URL 支持T或# 默认FLOW输入项 输入需要打开的网址URL 超时时间 支持T或# 打开网页超时时间 执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待的时间 UserAgent 支持T或# User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器

秒变高手:玩转CentOS 7软件更换的方法大全

在 CentOS 7 中更换软件源可以通过以下步骤完成。更换源可以加快软件包的下载速度,特别是当默认源速度较慢时。以下是详细步骤: 前言 为了帮助您解决在使用CentOS 7安装不了软件速度慢的问题,我们推出了这份由浪浪云赞助的教程——“CentOS7如何更换软件源加快下载速度”。 浪浪云,以他们卓越的弹性计算、云存储和网络服务受到广泛好评,他们的支持和帮助使得我们可以将最前沿的技术知识分

vue 父组件调用子组件的方法报错,“TypeError: Cannot read property ‘subDialogRef‘ of undefined“

vue 父组件调用子组件的方法报错,“TypeError: Cannot read property ‘subDialogRef’ of undefined” 最近用vue做的一个界面,引入了一个子组件,在父组件中调用子组件的方法时,报错提示: [Vue warn]: Error in v-on handler: “TypeError: Cannot read property ‘methods

JavaEE应用的组件

1、表现层组件:主要负责收集用户输入数据,或者向客户显示系统状态。最常用的表现层技术是JSP,但JSP并不是唯一的表现层技术。 2、控制器组件:对于JavaEE的MVC框架而言,框架提供一个前端核心控制器,而核心控制器负责拦截用户请求,并将用户请求转发给用户实现的控制器组件。而这些用户实现的控制器则负责处理调用业务逻辑方法,处理用户请求。 3、业务逻辑组件:是系统的核心组件,实现系统的业务逻辑

【Vue】关于Vue3的生命周期

目录 Vue3中新增了一个setup生命周期函数:(1) setup执行的时机是在beforeCreate生命周期函数之前执行,在setup函数中是不能通过this来获取实例的;(2) 为了命名的统一性,将beforeDestroy 改名为 beforeUnmount,destroyed 改名为 unmounted 生命周期函数: setup —— 不能通过this来获