美文网首页程序员
react 源码解析之createElement(一)

react 源码解析之createElement(一)

作者: 哎哟码呀 | 来源:发表于2020-03-08 14:31 被阅读0次

想要弄懂react,首先我们得了解如下几个方法:
1、react 核心API (createElement, Component,ReactDom)
2、setState核心
3、diff算法
当然本文先对createElement进行解析,文章持续更新中

一 、createElement

react 官网地址:https://reactjs.org/
首先我们需要去官网看下,认识一下在线解析。

勾选前的样子
官网一个简单的例子,右上角有一个勾选项,取消勾选后会显示如下:
取消勾选后的样子
我们可以发现,jsx帮我们做了一些事情,使得我们写法更简单了
render() {
    return (
      <div>
        Hello {this.props.name}
      </div>
    );
  }

转成了

  render() {
    return React.createElement(
      "div",
      null,
      "Hello ",
      this.props.name
    );
  }

并且用 React.createElement() 这个方法去创建render可以渲染的东西(我们称它为vdom, 虚拟dom)
createElement()参数有:

//React.createElement(type,props,[...children]);
  render() {
    return React.createElement(
      "div",//标签名字
      null,//div的属性如className等
      "Hello ",//子元素的内容
      this.props.name //子元素的属性
    );
  }

如果有很多子元素的话,会多次使用createElement 来创建,type 分为:
div,也就是浏览器可以识别的类型
hello:则是纯文本标签类型,如果是纯文本,其实是没有type的。
对于createElement来说,不同的标签会创建不同的内容:

class HelloMessage extends React.Component {
  render() {
    return (
      <div>
        Hello {this.props.name}
        <div> haha </div>
        <MyComp> haha </MyComp>//自定义类组件
      </div>
    );
  }
}

ReactDOM.render(
  <HelloMessage name="Taylor" />,
  document.getElementById('hello-example')
);

会被转成如下代码:

class HelloMessage extends React.Component {
  render() {
    return React.createElement(
      "div",
      null,
      "Hello ",
      this.props.name,
      React.createElement(//子div
        "div",
        null,
        "haha"
      ),
      React.createElement(//自定义组件MyComp
        MyComp,//自定义组件类型
        null,//属性
        "haha"//child:纯文本标签
      )
    );
  }
}

ReactDOM.render(React.createElement(HelloMessage, { name: "Taylor" }), document.getElementById('hello-example'));

通过createElement把这么一系列的嵌套的标签,转成虚拟dom(vdom,就是一堆js对象),然后通过render对这些对象的解析,来渲染到浏览器上。
问题:
1、虚拟dom是什么 (vdom)
用来描述我们dom结构的js对象。

你肯定会有疑问,为什么我们需要使用jsx,为什么不直接通过createElement来写代码呢?
答案:其实是可以的,但是你觉得哪个写起来更方便?当然是

  <div>haha</div>

这样方便了,不然每次你都 createElement ,写起来很麻烦,而且很容易出错,不严谨,jsx通过编译器的校验,帮我们快速的找出语法错误。

二、createElement简易源码解析

接下来我们来看下源码,createElement里面到底实现了哪些功能,下面代码是通过过滤筛选的简易的源码,避免看晕了。我加了一些注释便于理解。

import {
    VELEMENT,
    VSTATELESS,
    VCOMPONENT
} from './constant'
import { createVnode } from './virtual-dom'//创建虚拟节点需要

export default function createElement(type, props, ...children) {
    let vtype = null;//虚拟type,需要手动去判断标签的类型,上面说过,有纯文本类型,自定义组件类型等
    if (typeof type === 'string') {//类似div这种标签,type是字符串
        vtype = VELEMENT
    } else if (typeof type === 'function') {//函数组件,我们自定义的组件都是函数类型的,别问我为什么,我也不好说,请看【类组件&&函数组件】 图。
        if (type && type.isReactComponent) {//通过react创建出来的自定义组件都会给它加上一个isReactComponent,意味着是类组件
            vtype = VCOMPONENT //类组件
        } else {
            vtype = VSTATELESS //函数组件
        }
    } else {
        throw new Error(`React.createElement: unexpect type [ ${type} ]`)
    }

    let key = null
    let ref = null
    let finalProps = {}
    if (props != null) {
        for (let propKey in props) {
            if (!props.hasOwnProperty(propKey)) {
                continue
            }
            if (propKey === 'key') {
                if (props.key !== undefined) {
                    key = '' + props.key
                }
            } else if (propKey === 'ref') {
                if (props.ref !== undefined) {
                    ref = props.ref
                }
            } else {
                finalProps[propKey] = props[propKey]
            }
        }
    }


    finalProps.children = children //赋值子类

    return createVnode(vtype, type, finalProps, key, ref) //开始创建虚拟节点(先创建虚拟节点,创建完了以后,通过render绘制到页面上,是这么一个流程)
}
类组件&&函数组件

上图解释为啥类组件都是function。
大概createElement帮我们做了这些事情,欢迎大家关注我的公众号一起讨论交流。


关注我哦~

相关文章

网友评论

    本文标题:react 源码解析之createElement(一)

    本文链接:https://www.haomeiwen.com/subject/vlyddhtx.html