[React源码系列3]React组件初渲染原理

564 阅读2分钟

一、组件

组件可以将UI切分成一些独立的、可复用的部件,这样我们就只需要专注于每个单独的部件开发。组件的概念类似于 JS函数 ,它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。

components.png

二、React组件

2.1 函数组件

函数式组件就是通过编写 JavaScript 函数来定义的组件,通过接受一个props对象 并返回一个React元素来实现组件。

function Welcome(props){
    return <h1>Hello,{props.name}</h1>
}

// <Welcome name='Tom'></Welcome>

2.2 类组件

类组件是通过 ES6class 来定义的组件,类组件相较于函数组件有一些额外的特性,这个我们会在下节组件更新中详细介绍。

class Welcome extends React.Component {
    render(){
        return <h1>Hello,{this.props.name}</h1>
    }
}

这两个组件初渲染的结果是等价的

三、组件的初渲染原理

React中组件分为两类,一类是内置的原生组件,像div、p、span这些原生组件的type 是字符串,第二类是自定义组件,他的 type 类型是一个函数

3.1 函数组件

函数组件编译后结果

  • $$typeof: Symbol(react.element) 代表这个 JSX 是个组件
  • 传入的 name 会被挂在 props
  • type 属性的值是一个函数

函数组件编译.png

3.2 类组件

  • 类组件需要注意的是,type的原型上 isReactComponent 属性使用来标识该元素是否为类组件

类组件编译.png

3.3 组件初渲染原理

组件初渲染.png

// 接着上一篇文章,修改createDOM代码
function createDOM(vdom){
    let {type,props} = vdom;
    let dom;
    if(type === REACT_TEXT){
        dom = document.createTextNode(props.content);
    }else if(typeof type === 'function'){ // 组件
        if(type.isReactComponent){  // 类组件
            return mountClassComponent(vdom);
        }else{ 						// 函数组件
            return mountFunctionComponent(vdom);
        }
    }else{
        dom = document.createElement(props.content);
    }
    
    if(props){
        updateProps(dom,{},props);
        if(typeof props.children == 'object' && props.children.type){
           render(props.children,dom)
        }else if(Array.isArray(props.children)){
            reconcileChildren(props.children,dom)
        }
    }
    vdom.dom = dom
    return dom
}

3.4 函数组件的挂载

函数组件的挂载原理就是将 type 执行得到的 vdom 传入到 createDOM 中生成真实DOM

function mountFunctionComponent(vdom){
    const [type,props] = vdom;
    const renderVdom = type(props);
    return createDOM(renderVdom);
}

3.5 类组件的挂载

类组件的父类 Component 的原型上有一个属性 isReactComponent 值是一个空对象

3.5.1 Component

Component.js 实现简易 Component

export class Component {
    static isReactComponent = {}	// 用于标识类组件
    constructor(props){
        this.props = props
    }
}

3.5.2 挂载类组件

类组件的挂载原理,先通过 new type 得到类的实例,在调用实例的 render 方法生成vdom,最后将得到的 vdom 传入到 createDOM 中生成真实DOM

function mountClassComponent(vdom){
    const [type,props] = vdom;
    const classInstance = new type(props);
    const renderVdom = classInstance.render(renderVdom);
    return renderVdom
}