What is React
A JavaScript library for building user interfaces
基本概念
- VIRTUAL DOM
React render执行的结果并不是真正的DOM节点,只是是轻量级的JavaScript对象,我们称之为virtual DOM。虚拟DOM是React的一大亮点,具有batching(批处理)和高效的Diff算法。使用Virtual dom在性能上不会比纯手动优化的DOM操作更快,使用Virtual DOM能在不需要手动优化的情况下,保证过得去的性能,从而提高代码的可维护性和开发效率。这让我们可以无需担心性能问题而随时“刷新”整个页面,由虚拟DOM来确保只对界面上真正变化的节点进行实际的DOM操作。
下图是浏览器的工作流:
a.Create DOM tree:浏览器的渲染引擎根据html的elements,生成Dom node,组成Dom tree
b.Create Render tree:浏览器解析外部CSS文件和元素的inline样式,结合Dom tree的nodes,生成render tree
c.layout:render tree上每一个node生成在屏幕上的具体位置的坐标值
d.painting:绘制
如果直接操作Dom,每次操作都会触发整个渲染流程,如果连续修改50个节点,那就会造成50次重新渲染,这会造成不必要的渲染消耗。我们可以自己编写逻辑,将每个Dom操作汇总到一个Dom fragment,再传递给Dom tree。但这样我们就得自己去记录哪些节点改变,哪些没有改变,这显然开发效率太低,所以我们可以把这个工作抽象一下,于是就有了virtual dom。
virtual dom这个抽象层的作用就是将这件事自动化、抽象化,通过Diff算法计算出需要改变的节点,使用batching批处理多个节点的改动,然后操作Dom树进行渲染,避免不必要的重新渲染。
- JSX
JSX just provides syntactic sugar for “React.createElement(component, props, …children)”
JSX是一个语法糖实际上就是封装了React.createElement,使用JSX可以提高代码的可读性和开发效率 - Component
无论是复杂的元素还是简单的元素,都定义为组件。通过组合组件的方式可以构建容易维护、高复用性的组件。 - one-way reactive data flow
React 的单向数据流的设计让前端 bug 定位变得简单,页面的UI和数据的对应是唯一的,我们可以通过定位数据变化就可以定位页面展现问题。
React Render Mechanism 渲染机制源码解析
Render analyse
React有3种element,Text element、Basic element 基本元素、Custom element 自定义元素。
Render DOM implement analyse
Basic element 基本元素渲染解析
|
|
- 创建虚拟DOM实例
React.createElement:
use createElement function to create a virtual dom -> React.createElement
- keep the key to identify element
- copy the config(attributes) to the props
- copy the children to the props.children
- call ReactElement function and send ‘type’,’key’,’props’ for initial a element object
2.将创建好的虚拟DOM实例通过React.render进行渲染
React.render:
- instantiateReactComponent
- init component instance
- mountComponent
- render component instance to html content
3.在React.render里,首先调用instantiateReactComponent方法,根据element渲染出component实例。
instantiateReactComponent:
- return ReactDOMTextComponent
- if(typeof node === ‘string’ || typeof node === ‘number’)
- return ReactDOMComponent
- if(typeof node === ‘object’ && typeof node.type === ‘string’)
- return new ReactCompositeComponent
- if(typeof node === ‘object’ && typeof node.type === ‘function’)
4.接着调用mountComponent,将instantiateReactComponent得到的component实例渲染成原生的Dom结构
ReactDOMComponent.prototype.mountComponent:
- assign type : tagOpen = ‘<’ + ‘dic’
- add props : tagOpen += propKey + props[propKey]
- recursive child node to be content : each(content += childComponentInstance.mountComponent)
- result : tagOpen + ‘>’ + content + tagClose
React的伪代码
渲染结果
HelloWorld组件通过React.render进行解析最后变成Render Tree
|
|
渲染流程图
Render Composite implement analyse
Custom element自定义元素渲染解析
自定义元素的渲染流程有两点不一样,第一增加了创建自定义类的环节,第二,在最后一步“mountComponent”会递归调用,将父组件的每一个子组件进行渲染解析
|
|
1.创建自定义类
React.createClass
- Constructor a child class
- inserit to ReactClasss
- Constructor.prototype = new ReactClass();
- extend Constructor.prototype,spec
ReactCompositeComponent.prototype.mountComponent
- initialize public class by ‘ReactClass’ function
- var inst = new ReactClass(publicProps);
- life cycle callback
- inst.componentWillMount()
- call render to instance a element
- renderedElement = inst.render() 返回的可能是一个DOM element
- getting component instance
- renderedComponentInstance = instantiateReactComponent(renderedElement)
- get rendered result by renderedComponentInstance
- renderedComponentInstance.mountComponent
- life cycle callback
- inst.componentDidMount()
React Native ReRender mechanism 重新渲染机制
一个react组件的重新渲染,是通过setState方法的调用,导致stated改变发起的
ReactClass.prototype.setState
- call ‘this._reactInternalInstance.receiveComponent(null, newState);’
All the component implement the ‘receiveComponent’ the handle the render of themself. the DOMComponent is the most complexest ,it used diff algorithm to handle the child node update.
state改变后会调用组件的receiveComponent方法进行element和属性的更新
ReactCompositeComponent.prototype.receiveComponent
- update element 更新element对象
- bind the new state and props 生成心的state和props
- judge whether update or reRender the element by type and key
ReactDOMTextComponent.prototype.receiveComponent
- if the text string is change, update content of the node 如果text的内容有变化,刷新节点
ReactDOMComponent.prototype.receiveComponent
- update element 更新element对象
- updateDOMProperties 更新属性
- updateDOMChildren 更新子节点
implementation of DomComponent RecevieComponent
首先是更新Properties
ReactDOMComponent.prototype._updateDOMProperties
- remove the old attribute
- remove the event monitor
- add the new attribute
- add the new event monitor
接着是更新子组件
ReactDOMComponent.prototype._updateDOMChildren
- diff
- user diff algorithm the find out diffrence and add the diffrence to the diffQueue
- patch
- traversal diffQueue for removing the changed node , inserting the new note and inserting the modified node
analyse diff and patch
更新子组件时,使用diff算法计算出需要移动、插入、删除的组件,大部分没有变动的组件不做更新。
ReactDOMComponent.prototype._diff
- getting the previous component of childrend
- generating the next component of childrend
- assign the new children
- compare the previous and next components
- previous Child handle
- if these is the same component and element , move it (MOVE_EXISTING)
- if these is the same component but not the same element, remove element (REMOVE_NODE)
- remove event monitor of previous child
- if a previous child which was not exist in nest queue, delete the component
- next child handle
- add the new node (INSERT_MARKUP)
- previous Child handle
ReactDOMComponent.prototype._patch
- delete REMOVE_NODE nodes
- delete MOVE_EXISTING nodes
- insert INSERT_MARKUP nodes
- insert MOVE_EXISTING nodes
参考
reactjs源码分析-上篇
reactjs源码分析-下篇(更新机制实现原理)
React为什么要使用Virtual DOM
React虚拟DOM浅析
React 介绍
渲染树构建、布局及绘制
浏览器工作原理
How WebKit Works