如下,是我在2018 React Conf的分享内容,但愿对你们有所帮助。能够先在官网下载个人ppt对照看,效果更佳哦~☺。react
官网:https://react.w3ctech.com/数组
不少人都使用过React,可是不多人能说出它内部的渲染原理。有人会说,会用就好了,知道渲染原理有必要么?其实渲染原理决定着性能优化的方法,只有在了解原理以后,才能彻底理解为何这样作能够优化性能。正所谓:知其然,而后知其因此然。浏览器
废话很少说,下面咱们就开始吧~性能优化
本篇文章,将会分为四部分介绍:babel
JSX如何生成elementapp
当咱们写下一段JSX代码的时候,react是如何根据咱们的JSX代码来生成虚拟DOM的组成元素element的。dom
element如何生成真实DOM节点异步
再生成elment以后,react又如何将其转成浏览器的真实节点。这里会经过介绍首次渲染以及更新渲染的流程来帮助你们理解这个渲染流程,函数
性能优化性能
结合渲染原理,经过实际例子,看看如何优化组件。
React 16异步渲染方案
到目前为止,这些优化组件的方法还不能解决什么问题,因此咱们须要引入异步渲染,以及异步渲染的原理是什么。
1、JSX如何生成element
这里是一段写在render里的jsx代码。
首先,它会通过babel编译成React.的表达式。
这个方法是作什么的呢?
其实从它的名字就能够看出,这是用来生成element的。element在React里,其实就是组成虚拟DOM 树的节点,它用来描述你想要在浏览器上看到什么。
它的参数有三个:
一、type -> 标签
二、attributes -> 标签属性,没有的话,能够为null
三、children -> 标签的子节点
这个React.的表达式会在render函数被调用的时候执行,换句话说,当render函数被调用的时候,会返回一个element。
说了那么久element,这个element究竟长什么样呢?
其实,它就是一个对象,以下:
咱们来观察一下这个对象的children,如今有三种类型:
一、string
二、原生DOM节点
三、React Component - 自定义组件
除了这三种,还有两种类型:
四、fale ,null, undefined,number
五、数组 - 使用map方法的时候
这里须要记住一个点:element不必定是Object类型。
2、element如何生成真实节点
顺利获得element以后,咱们再来看看React是如何把element转化成真实DOM节点的。
首先,须要去初始化element,初始化的规则以下:
先判断是否为Object类型,是的话,看它的type是不是原生DOM标签,是的话,给它建立ReactDOMComponent的实例对象,其余同理。
这时候有的人可能会有所疑问:这些个ReactDOMComponent, ReactCompositeComponentWrapper怎么开发的时候都没有见过?
其实这些都是React的私有类,React本身使用,不会暴露给用户的。它们的经常使用方法有:mountComponent,updateComponent等。其中mountComponent 用于建立组件,而updateComponent用于用户更新组件。而咱们自定义组件的生命周期函数以及render函数都是在这些私有类的方法里被调用的。
既然这些私有类的方法那么重要咱们就先来简单了解一下吧~
ReactDOMComponent
首先是ReactMComponent的mountComponent方法,这个方法的做用是:将element转成真实DOM节点,而且插入到相应的container里,而后返回markup(realDOM)。
由此可知ReactDOMComponent的mountComponent是element生成真实节点的关键。
下面看个栗子它是怎么作到的吧。
假设有这样一个type类型是原生DOM的element:
简单mountComponent的实现:
其实实现的过程很简单,就是根据type生成domElement,再将子节点append进来返回。固然,真实的mountComponent没有那么简单,感兴趣的能够本身去看源码啦。
这里须要记住的一个点是:这个类的mountComponent方法会本身操做浏览器DOM元素。
讲完ReactDOMComponent,再来看看ReactCompositeComponentWrapper。
ReactCompositeComponentWrapper
这个类的mountComponent方法做用是:实例化自定义组件,最后是经过递归调用到ReactDOMComponent的mountComponent方法来获得真实DOM。
注意:也就是说他本身是不直接生成DOM节点的。
那这个递归是一个怎样的过程呢?咱们经过首次渲染来看下。
首次渲染
假设咱们有一个Example的组件,它返回<div>hello world</div> 这样一个标签。
首次渲染的过程以下:
首先从React.render开始,因为咱们刚刚说,render函数被调用的时候会返回一个element,因此此时返回给咱们的element是:
因为这个type是一个自定义组件类,此时要初始化的类是ReactCompositeComponentWrapper,接着调用它的mountComponent方法。这里面会作四件事情,详情能够看上图。其中,第二步的render的获得的element为:
因为这个type是一个原生DOM标签,此时要初始化的类是ReactDOMComponent。接下来它的mountComponent方法就能够帮咱们生成对应的DOM节点放在浏览器里啦。
这时候有人可能会有疑问,若是第二步render出来的element 类型也是自定义组件呢?
这时候它就会去调用ReactCompositeComponentWrapper的mountComponent方法,从而造成了一个递归。无论你的自定义组件嵌套多少层,最后总会生成原生dom类型的element,因此最后必定能调用到ReactDOMComponent的mountComponent方法。
感兴趣的能够本身在打断点看下这个递归的过程。
由我打的断点图能够看出在ReactCompositeComponent的mountComponent被调用屡次以后,最后调用到了ReactDOMComponent的mountComponent方法。
到这里,首次渲染的过程就基本讲完了:-D。
可是还有一个问题:前面咱们说自定义组件的生命周期跟render函数都是在私有类的方法里被调用的,如今只看到render函数被调用了,那么首次渲染时候生命周期函数 componentWillMount 跟 componentDidMount 在哪被调用呢?
由图可知,在第一步获得instance对象以后,就会去看instance.componentWillMount是否有被定义,有的话调用,而在整个渲染过程结束以后调用componentDidMount。
以上,就是渲染原理的部分,让咱们来总结如下:返回搜狐,查看更多