重新完成一个简易版React(一)

写在开首

工作中运用react也很长一段时间了,虽然对它的用法,道理有了一定的相识,然则总觉得停留在外表。本着知其然知其所以然的立场,我试着去看了react源码,几天下来,发明并不能看懂,反而越发云里雾里了- -!。既然看不懂,那就看看社区先辈们写的一些源码剖析文章以及完成思绪吧,又这么过了几天,总算是摸盘点思绪,因而在参考了先辈们的基础上,完成了一个简易版的react。
这个系列我盘算分为3节,第一节引见下完成的思绪以及构造,第二节讲衬着,第三节讲更新。

进入正题

尽人皆知,react的中心是Virtual DOM,所以,我们的思绪也是围绕着Virtual DOM睁开,包括Virtual DOM模子的竖立,生命周期的治理,对照差别的diff算法,将Virtual DOM转化为原生DOM并展现的patch要领等,setState异步机制以及react合成事宜因为还没有研讨到,临时先疏忽,事宜处置惩罚跟某位先辈的思绪一样,也是运用jquery事宜替代,这里我们主要以完成衬着,更新为主,相信你在看完这个系列后,能对react的运转道理有一定明白。
项目地点:https://github.com/LuSuguru/f…,以下的一切代码都是经由过程es6编写,切勿用在临盆环境。

Virtual DOM的完成

React的一切都基于Virtual DOM,我们第一步天然先完成它,以下:

/**
 * @param type :代表当前的节点属性
 * @param key :用来标识element,用于优化今后的更新
 * @param props:节点的属性
 */
function VDom(type, key, props) {
  this.type = type
  this.key = key
  this.props = props
}
// 代码地点:src/react/reactElement.js  

完成了vDom后,理所须要一个要领来将我们写的元素转化为vDom。平常我们都是JSX来建立元素的,但它只不过是React.createElment的语法糖。所以,接下来,我们要完成的就是createElement要领:

function createElement(type, config, ...children) {
  const props = {}

  config = config || {}
  // 猎取key,用来标识element,轻易今后高效的更新
  const { key = null } = config
 
  let propName = ''

  // 复制config里的内容到props
  for (propName in config) {
    if (config.hasOwnProperty(propName) && propName !== 'key') {
      props[propName] = config[propName]
    }
  }

  // 转化children
  if (children.length === 1 && Array.isArray(children[0])) {
    props.children = children[0]
  } else {
    props.children = children
  }

  return new VDom(type, key, props)
}
// 代码地点:src/react/reactElement.js  

这段代码也异常简朴,依据我们传入的参数,天生对应的vDom

ReactComponent的完成

我们所建立的VDom范例分为3种:

  • 文本范例
  • 原生DOM范例
  • 自定义范例

差别的范例,一定有差别的衬着和更新逻辑,我们把这些逻辑与vDom一同,封装成对应的ReactComponent类,经由过程ReactComponent类掌握vDom,这里我把它们命名为ReactTextComponent,ReactDomComponent,ReactCompositeComponent,离别对应三种范例。
首先是基类ReactComponet:

// component基类,用来处置惩罚差别的假造dom更新,衬着
class Component {
  constructor(element) {
    this._vDom = element
    // 用来标识当前component
    this._rootNodeId = null
  }
}
// 代码地点:src/react/component/ReactComponent.js  

接着再让差别范例的component继续这个基类,每种component范例都有mount和update两个要领,用来实行衬着和更新

class ReactDomComponent extends ReactComponent {
    // 衬着
  mountComponent() {}

  // 更新
  updateComponent() {}
}
class ReactCompositeComponent extends ReactComponent {
    // 衬着
  mountComponent() {}

  // 更新
  updateComponent() {}
}
class ReactTextComponent extends ReactComponent {
    // 衬着
  mountComponent() {}

  // 更新
  updateComponent() {}
}

进口的完成

完成了ReactComponent后,我们天然须要一个进口去获得ReactComponent并挪用它的mount。在运用React时,一般都是经由过程

import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component {
}

ReactDOM.render(<App />, document.getElementById('root'))

这段代码来充任衬着的进口,下面我们来完成这个进口,(为了轻易申明,我把render要领也放在了React对象中)

import Component from './Component'
import createElement from './ReactElement'
import instantiateReactComponent from './component/util'
import $ from 'jquery'

const React = {
  nextReactRootIndex: 0, // 标识id,肯定每一个vDom的唯一性
  Component, // 一切自定义组件的父类
  createElement, // 建立vdom

  render(vDom, container) { // 进口
    var componentInstance = instantiateReactComponent(vDom) //经由过程vDom天生Component
    var markup = componentInstance.mountComponent(this.nextReactRootIndex++)

    container.innerHTML = markup
    $(document).trigger('mountReady')
  }
}
// 代码地点:src/react/index.js  

因为衬着和更新都已封装在差别的ReactComponent里,所以,这里也须要一个要领,依据差别的vDom范例天生对应的ReactComponent,下面我们就来完成这个要领:

// component工场,用来返回一个component实例
function instantiateReactComponent(node) {
  // 文本节点的状况
  if (typeof node === 'string' || typeof node === 'number') {
    return new ReactTextComponent(node)
  }

  // 浏览器默许节点的状况
  if (typeof node === 'object' && typeof node.type === 'string') {
    return new ReactDomComponent(node)
  }

  // 自定义的元素节点
  if (typeof node === 'object' && typeof node.type === 'function') {
    return new ReactCompositeComponent(node)
  }
}

然后再挪用进口ReactComponent的mount要领,猎取衬着内容,再将其衬着出来就行。

总结

《重新完成一个简易版React(一)》

以上就是完成一个react的整体思绪,下节我们重点放在差别ReactComponet的mount上。
下一节地点:https://segmentfault.com/a/11…

参考资料,谢谢几位先辈的分享:
https://www.cnblogs.com/sven3…
https://github.com/purplebamb…
陈屹 《深切React手艺栈》

    原文作者:NANA
    原文地址: https://segmentfault.com/a/1190000013504156
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞