前端知识库Reactjs进阶系列(组件的加载过程)

简介: 最近在项目中遇到react的组件多次渲染的问题,最后虽然顺利解决了但也同时发现了自己对于react生命周期的不熟悉,于是便找出react的文档重新去了解下,重新学习之后总结为以下两个主要知识点:react组件的整个渲染流程 react组件更新的注意点。

前言


最近在项目中遇到react的组件多次渲染的问题,最后虽然顺利解决了但也同时发现了自己对于react生命周期的不熟悉,于是便找出react的文档重新去了解下,重新学习之后总结为以下两个主要知识点:react组件的整个渲染流程 react组件更新的注意点。

生命周期流程


网络异常,图片无法展示
|

由上图可以了解到react组件的生命周期大致可以分为三个阶段:

  • 挂载(初始化)阶段
  • 更新(运行中)阶段
  • 卸载阶段

DOM挂载阶段

  • defaultProps:给父组件传递过来的props赋初期值
Demo.defaultProps={
   demo:"test"
}
  • constructor:数据的初始化,它接受两个参数:props和context,当想在函数内部使用这两个参数时,需使用super()传入这两个参数。
1.只要使用了constructor()就必须写super(),否则会导致this指向错误。
   2.在constructor生命周期中可以直接设置state的值。
  constructor(props) {
    super(props);
    //只有此种状态可以直接设置state
    this.state = {};
  }
  • componentWillMount:用于挂在之前,在组件的整个生命周期内只执行一次,此时可以进行setState
  • componentDidMount:用于组件在DOM成功渲染之后执行,此生命周期中可以获取真实的dom元素,在组件的整个生命周期内只执行一次,另外官方文档建议在这个生命周期适合进行异步请求
import axios from 'axios'
componentDidMount(){
   document.querySelector("#root")
   //异步请求
   aixos.get('/demo')
        .then(res=>{})
}

为什么官方建议在componentDidMount生命周期中进行异步请求?

正常点逻辑是在越早的生命周期进行请求越好,例如vue中建议在created(beforeCreated时data还没挂载)生命周期中进行异步请求,而在react中componentDidMount之前还有componentWillMount和constructor,为何不再这两个生命周期中调用呢,首先我们进行的异步请求一般都会将获取的数据渲染到组件上及调用setState,我们下面以这个为基础来分析。

  • constructor中为何不建议进行异步请求,个人认为原因有两点:1.不符合我们日常的编码规范 2.此处进行setState无意义。
  • componentWillMount将会在16.x慢慢被废弃掉,所以不建议使用
  • 在此生命周期中进行异步请求因为此生命周期调用setState会进行render渲染

综上所述还是在componentDidMount中进行异步请求比较合理。

组件挂载中是如何将虚拟DOM转化成真实DOM的?

在组件挂载之前React组件是一个JavaScript对象也就是我们所说的虚拟DOM。React以二叉树的形式表示整个UI结构的方式创建自己的虚拟DOM。它将虚拟DOM树保存到内存中。结构如下

//react组件中html
<div class="demo">
  <p class="item">ui components</p>
</div>
//JavaScript表示都数据结构
{
  tagName: 'div', // 节点标签名
  props: { // DOM的属性,用一个对象存储键值对
    class: 'demo'
  },
  children:[
     {tagName:"p",props:{class:"item"}}
  ]
  }

虚拟DOM vs 直接操作真实DOM?

在正常的前端页面中,如果是整个页面数据都发生变化,此时我们通过重置整个html是合理都,但是如果仅仅是页面某一快数据发生变化,那我们此时重置整个页面都操作就时分浪费性能了。对于虚拟DOM而言只用更新对象上相关数据后对页面都部分进行重新渲染即可。比较如下:

  • 原生DOM: render html string + 重新创建所有 DOM 元素
  • Virtual DOM: render Virtual DOM + diff + 必要的 DOM 更新

DOM更新

当我们使用setState或者父组件的props改变时候会触发组件的更新,此时生命周期如下:

  • componentWillReceiveProps(方法即将过时,不在过多介绍)
  • shouldComponentUpdate:参数如下nextProps(即将更新的props), nextState(即将更新的state) 注意:如果 返回值为 false,则不会调用 componentDidUpdate()。
shouldComponentUpdate(nextProps,nextState){
    console.log('----should update---')
    return false
}
componentDidUpdate(){
    console.log('-----did update------')
}
  • componentWillUpdate(方法即将过时,不在过多介绍)
  • componentDidUpdate :组件更新时会触发次钩子函数。例如:setState或父元素的props改变。
  • render
1.在react组件中同事多次执行setState最终只会render一次
2.方法是 class 组件中唯一必须实现的方法
3.当被调用时,返回以下类型之一:React元素 数组或fragments 字符串或数值类型(被渲染成文本节点) 布尔类型或 null(不渲染)
4.shouldComponentUpdate() 返回 false,则不会调用 render()
5.render为纯函数,不修改组件 state 的情况下每次调用都返回相同的值,并且不会与浏览器交互。

为何在react不能直接改变state?

直接使用this.state是能够改变state的值的但是并不会触发组件的更新,这样会导致两个问题:组件页面的内容和组件的状态不一致 组件内的状态不可控。所以我们在进行状态更新时候需要调用setState方法来进行。

为何直接给state赋值不起作用呢?

根据上一个问题我们知道了setState都执行步骤,如何我们直接给状态赋值是不会将状态放入state中的。因此就不会触发react的更新。

setState是同步的还是异步的呢?

  • setState 只在合成事件和钩子函数中是“异步”的,在原生事件和 setTimeout 中都是同步的。
  • setState本身的代码是同步的,知识因为react的合成事件和钩子函数的调用顺序在更新之前,导致在合成事件和钩子函数中没法立马拿到更新后的值

组件更新原理

在react中的组件加载中,更新操作是组件不可避免的操作,在以上内容中我们已经大概了解了setState的执行步骤,本节主要来了解过在更新过程中react是通过什么方式实现其复杂的组件新。

为何setState触发组件更新可能是异步对?

执行步骤:

  • 在函数中调用this.setState({demo:"demo"})
  • 此时奖setState中的新状态存入pending队列中
  • 判断状态是否需要批量更新
  • 如果是则等所有带新状态都保存在pending在更新(updateComponent)
  • 如果不是则开始更新新状态

以上是我们在调用setState时候的执行步骤,下面我们来了解下react调用setState是如何触发组件更新的:

  • setState挂载到组件原型链上,
ReactComponent.prototype.setState = function (partialState, callback) {
  !(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null) ? "development" !== 'production' ? invariant(false, 'setState(...): takes an object of state variables to update or a function which returns an object of state variables.') : _prodInvariant('85') : void 0;
  this.updater.enqueueSetState(this, partialState);
  if (callback) {
    this.updater.enqueueCallback(this, callback, 'setState');
  }
};   
  • 执行setState时调用enqueueSetState

什么情况下setState是同步的呢?

在我们使用React封装的事件时会进入一个事务,这是不会直接触发batch update更新 。 而当我们使用原生的事件机制时(比如 addEventListener ),由于缺少了React的封装,会使得 setState 直接触发 batch update更新,从而同步更新state。

DOM销毁

  • componentWillUnmount:组件销毁时触发的生命周期。

在react生命周期中componentWillUnmount虽然我们很少在此处进行操作,但是在某些场景下可以发挥很大到作用比如在离开组件时候结束一个定时器或是解绑一个全局事件。

总结


通过上文的总结,我对react对组件加载有了更深刻对认识,其过程大概可分为三大阶段:挂载,更新,卸载。对于react组件的加载我认为以下几点是需要我们关注的:挂载阶段的虚拟Dom是如何渲染成真实DOM的,更新时候setState做了什么。


相关文章
|
前端开发 JavaScript API
(前端3D模型开发)网页三维CAD中加载和保存STEP模型
本文介绍了如何使用`mxcad3d`库在网页上实现STEP格式三维模型的导入与导出。首先,通过官方教程搭建基本项目环境,了解核心对象如MxCAD3DObject、Mx3dDbDocument等的使用方法。接着,编写了加载和保存STEP模型的具体代码,包括HTML界面设计和TypeScript逻辑实现。最后,通过运行项目验证功能,展示了从模型加载到保存的全过程。此外,`mxcad3d`还支持多种其他格式的三维模型文件操作。
1456 115
|
缓存 前端开发 UED
如何优化前端性能以提高加载速度
前端性能优化对提升网站加载速度至关重要,直接影响用户体验、SEO排名和转化率。本文介绍了优化前端加载速度的关键技巧,包括最小化HTTP请求、使用CDN、优化图片、利用浏览器缓存、压缩文件和实现懒加载。通过这些方法,可以显著减少页面加载时间,提高网站的整体性能和用户满意度。
|
前端开发 API 开发者
harmonyOS基础- 快速弄懂HarmonyOS ArkTs基础组件、布局容器(前端视角篇)
本文由黑臂麒麟(6年前端经验)撰写,介绍ArkTS开发中的常用基础组件与布局组件。基础组件包括Text、Image、Button等,支持样式设置如字体颜色、大小和加粗等,并可通过Resource资源引用统一管理样式。布局组件涵盖Column、Row、List、Grid和Tabs等,支持灵活的主轴与交叉轴对齐方式、分割线设置及滚动事件监听。同时,Tabs组件可实现自定义样式与页签切换功能。内容结合代码示例,适合初学者快速上手ArkTS开发。参考华为开发者联盟官网基础课程。
1210 75
harmonyOS基础- 快速弄懂HarmonyOS ArkTs基础组件、布局容器(前端视角篇)
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
984 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
Dart 前端开发
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
527 75
【05】flutter完成注册页面完善样式bug-增加自定义可复用组件widgets-严格规划文件和目录结构-规范入口文件-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
Dart 前端开发 容器
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
520 18
【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
监控 前端开发 数据可视化
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
@icraft/player-react 是 iCraft Editor 推出的 React 组件库,旨在简化3D数字孪生场景的前端集成。它支持零配置快速接入、自定义插件、丰富的事件和方法、动画控制及实时数据接入,帮助开发者轻松实现3D场景与React项目的无缝融合。
1054 9
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
|
缓存 前端开发 JavaScript
前端性能优化:提升网页加载速度的10个技巧
【10月更文挑战第25天】在互联网时代,网页加载速度直接影响用户体验和搜索引擎排名。本文介绍了10个提升网页加载速度的技巧,包括减少HTTP请求、启用压缩、使用CDN、延迟加载非关键资源、优化图片、减少重定向、使用浏览器缓存、优化CSS和JavaScript、异步加载JavaScript以及代码分割。通过这些方法,可以显著提高网页性能,改善用户体验。
3323 5
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
309 1
|
缓存 监控 前端开发
前端性能优化实战:从加载速度到用户体验
前端性能优化实战:从加载速度到用户体验