前端知识库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做了什么。


相关文章
|
2月前
|
缓存 前端开发 JavaScript
探索前端性能优化:从加载速度到用户体验的全面升级
探索前端性能优化:从加载速度到用户体验的全面升级
56 0
|
17天前
|
缓存 前端开发 JavaScript
前端性能优化:提升网页加载速度的10个技巧
【10月更文挑战第25天】在互联网时代,网页加载速度直接影响用户体验和搜索引擎排名。本文介绍了10个提升网页加载速度的技巧,包括减少HTTP请求、启用压缩、使用CDN、延迟加载非关键资源、优化图片、减少重定向、使用浏览器缓存、优化CSS和JavaScript、异步加载JavaScript以及代码分割。通过这些方法,可以显著提高网页性能,改善用户体验。
59 5
|
19天前
|
前端开发 JavaScript 开发者
揭秘前端高手的秘密武器:深度解析递归组件与动态组件的奥妙,让你代码效率翻倍!
【10月更文挑战第23天】在Web开发中,组件化已成为主流。本文深入探讨了递归组件与动态组件的概念、应用及实现方式。递归组件通过在组件内部调用自身,适用于处理层级结构数据,如菜单和树形控件。动态组件则根据数据变化动态切换组件显示,适用于不同业务逻辑下的组件展示。通过示例,展示了这两种组件的实现方法及其在实际开发中的应用价值。
27 1
|
22天前
|
缓存 前端开发 JavaScript
前端serverless探索之组件单独部署时,利用rxjs实现业务状态与vue-react-angular等框架的响应式状态映射
本文深入探讨了如何将RxJS与Vue、React、Angular三大前端框架进行集成,通过抽象出辅助方法`useRx`和`pushPipe`,实现跨框架的状态管理。具体介绍了各框架的响应式机制,展示了如何将RxJS的Observable对象转化为框架的响应式数据,并通过示例代码演示了使用方法。此外,还讨论了全局状态源与WebComponent的部署优化,以及一些实践中的改进点。这些方法不仅简化了异步编程,还提升了代码的可读性和可维护性。
|
30天前
|
前端开发 JavaScript
CSS样式穿透技巧:利用scoped与deep实现前端组件样式隔离与穿透
CSS样式穿透技巧:利用scoped与deep实现前端组件样式隔离与穿透
149 1
|
1月前
|
前端开发 JavaScript 开发者
Web组件:一种新的前端开发范式
【10月更文挑战第9天】Web组件:一种新的前端开发范式
38 2
|
1月前
|
前端开发 JavaScript Go
前端开发趋势:从响应式设计到Web组件的探索
【10月更文挑战第1天】前端开发趋势:从响应式设计到Web组件的探索
38 3
|
2月前
|
SpringCloudAlibaba JavaScript 前端开发
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
分布式组件、nacos注册配置中心、openfegin远程调用、网关gateway、ES6脚本语言规范、vue、elementUI
谷粒商城笔记+踩坑(2)——分布式组件、前端基础,nacos+feign+gateway+ES6+vue脚手架
|
2月前
|
缓存 边缘计算 前端开发
关于前端性能优化问题,认识网页加载过程和防抖节流
该文章详细探讨了前端性能优化的方法,包括理解网页加载过程、实施防抖和节流技术来提升用户体验和性能。
|
30天前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
127 2