美文网首页
React深入4 - 源码初探(jsx)

React深入4 - 源码初探(jsx)

作者: 申_9a33 | 来源:发表于2022-02-27 13:54 被阅读0次

    1. 先创一个包含函数组件,class组件,和html各种元素的jsx

    • 虚拟Dom(vnode) 是指用一个js对象来描述真实Dom(node),React 是通过bebal,将jsx,转换成vnode
    // src\main.tsx
    
    import React, { Component } from 'react';
    import { render } from 'react-dom';
    import './index.scss';
    
    interface IProps{
      name:string
    }
    
    function FuncationComponent(props:IProps) {
      return (
        <div className="border">
          <p>{props.name}</p>
        </div>
      );
    }
    
    // eslint-disable-next-line react/prefer-stateless-function
    class ClassComponent extends Component<IProps> {
      render(): React.ReactNode {
        return (
          <div className="border">
            <p>{this.props.name}</p>
          </div>
        );
      }
    }
    
    const jsx = (
      <div className="border">
        <h1>jsx title</h1>
        <a href="https://www.baidu.com/">链接</a>
        <FuncationComponent name="FuncationComponent" />
        <ClassComponent name="ClassComponent" />
      </div>
    );
    
    render(jsx, document.getElementById('root'));
    
    image.png

    2. 'react-dom' 里面的 render

    2.1 接受两个参数 jsx (vnode)和 原生element,我们打印vnode

    // src\react\react-dom.ts
    
    export function render(vnode:any, container:any) {
      console.log(vnode, 'vnode');
      // vnode -> node
      const node = createNode(vnode);
    
      // node -> container
      container.appendChild(node);
    }
    
    image.png
    • 可以看到vnode 主要由 type,key,ref,props组成
    • vnode如果是HTMLElement, type 就是HTMLElement的类型
    • vnode如果是文本,则直接放入字符串
    • vnode如果是FunctionComponent,ClassComponent, type则是一个函数
    • ClassComponent组件的prototype上会有 isReactComponent属性,用来区分class组件和函数组件

    2.2 createNode 将vnode 转换为node

    function createNode(vnode:any):any {
      let node;
    
      const { type, props } = vnode;
    
      switch (true) {
        case isString(type): {
          // HTMLElement 元素
          node = document.createElement(type); // 根据类型创建真实dom
          reconcileChildren(node, props.children); // 继续渲染子元素
          updateNode(node, props); // 将属性挂载在node上
          break;
        }
    
        case isFunction(type):
          // React函数组件,类组件
          node = type.prototype.isReactComponent
            ? updateClassComponent(vnode)
            : updateFunctionComponent(vnode);
          break;
    
        case type === undefined:
          // 普通文本
          node = document.createTextNode(vnode);
          break;
    
        default:
          node = document.createTextNode('');
          break;
      }
    
      return node;
    }
    
    • 根据上面type,大致把组件分为三类,HTMLElement,ReactComponent,textElement
    • HTMLElement,直接使用 document.createElement 创建即可,然后继续遍历子元素,执行render,同时将props挂载在node上
    • ReactComponent,函数组件直接执行,类组件先实例化后,执行内部的render函数,将返回的jsx,当作参数递归执行createNode
    • textElement,直接使用document.createTextNode

    2.3 类组件 Component

    export function Component(props:any) {
      this.props = props;
    }
    Component.prototype.isReactComponent = {};
    
    export default { Component };
    
    • 将props绑定到this中
    • 在prototype上标记自己是ReactComponet

    3.最终结果

    image.png
    源码

    相关文章

      网友评论

          本文标题:React深入4 - 源码初探(jsx)

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