浅谈从React渲染流程分析Diff算法

React中最神奇的部分莫过于虚拟DOM,以及其高效的Diff算法。这让我们可以无需担心性能问题而”毫无顾忌”的随时“刷新”整个页面,由虚拟DOM来确保只对界面上真正变化的部分进行实际的DOM操作。React在这一部分已经做到足够透明,在实际开发中我们基本无需关心虚拟DOM是如何运作的。然而,理解其运行机制不仅有助于更好的理解React组件的生命周期,而且对于进一步优化React程序也会有很大帮助。

1、什么是虚拟DOM

在React中,render执行的结果得到的并不是真正的DOM节点,结果仅仅是轻量级的JavaScript对象,我们称之为virtual DOM。

简单的说,其实所谓的virtual DOM就是JavaScript对象到Html DOM节点的映射;即使用JavaScript对象将Html结构表示出来,而这个对象就是virtual DOM。

eg:

Html:

<ul> <li>Item 1</li> <li>Item 2</li> </ul>

JavaScript对象表示(virtual DOM)

{ tagName: 'ul', props: { id: 'list' }, children: [ {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]}, {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]}, ] }

2、什么时候会生成到virtual DOM

React生命周期拥有装载、更新、卸载的三个阶段;附上一张React生命周期图

浅谈从React渲染流程分析Diff算法

前面提到:render执行的结果得到的并不是真正的DOM节点,结果仅仅是轻量级的JavaScript对象,即在render函数调用时将会创建出虚拟DOM;

class Tab extends React.Component { render() { React.createElement( 'p', { className: 'class'}, 'Hello React' ) } }

浅谈从React渲染流程分析Diff算法

通过React.createElemen创建出虚拟DOM,而该函数只在Render函数中调用,所以在React装载和更新的过程中才会有虚拟DOM的生成;至于挂载到真实DOM自然而然是ReactDom.render函数啦。

3、virtual DOM如何实现

实现其实很简单,主要是定义一个函数并把我们传进去的参数组成一个React元素对象,而type就是我们传进去的组件类型,可以是一个类、函数或字符串(如'div')

React大致源码:

function createElement(type, config, children) { let propName; const props = {}; let key = null; let ref = null; let self = null; let source = null; if (config != null) { if (hasValidRef(config)) { // 如果有ref,将它取出来 ref = config.ref; } if (hasValidKey(config)) { // 如果有key,将它取出来 key = '' + config.key; } self = config.__self === undefined ? null : config.__self; source = config.__source === undefined ? null : config.__source; for (propName in config) { if ( hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName) ) { // 将除ref,key等这些特殊的属性放到新的props对象里 props[propName] = config[propName]; } } } // 获取子元素 const childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = children; } else if (childrenLength > 1) { const childArray = Array(childrenLength); for (let i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } props.children = childArray; } // 添加默认props if (type && type.defaultProps) { const defaultProps = type.defaultProps; for (propName in defaultProps) { if (props[propName] === undefined) { props[propName] = defaultProps[propName]; } } } return ReactElement( type, key, ref, self, source, ReactCurrentOwner.current, props, ); } const ReactElement = function(type, key, ref, self, source, owner, props) { // 最终得到的React元素 const element = { // This tag allows us to uniquely identify this as a React Element $$typeof: REACT_ELEMENT_TYPE, // Built-in properties that belong on the element type: type, key: key, ref: ref, props: props, // Record the component responsible for creating this element. _owner: owner, }; return element; };

打印出组件:

浅谈从React渲染流程分析Diff算法

4、为什么需要使用virtual DOM

DOM管理历史阶段:

JS 或者 jQuery 操作 DOM: 当应用程序越来越复杂,需要在JS里面维护的字段也越来越多,需要监听事件和在事件回调用更新页面的DOM操作也越来越多,应用程序会变得非常难维护。

后来产出 MVC、MVP 的架构模式,期望从代码组织方式来降低维护难度。但是 MVC 架构并没办法减少维护的状态,也没有降低状态更新时需要对页面的更新操作,你需要操作的DOM还是需要操作,只是换了个地方。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/a2d398f6b1652c53b763aef5594eb252.html