jsx底层渲染机制,函数组件的底层渲染机制

jsx底层渲染机制!!

1.第一大步创建virtualDom

首先把我们编写的JSX语法,编译为虚拟DOM对象「virtualDOM」,这一步也分为两小步

虚拟DON对象∶框架自己内部构建的一套对象体系(对象的相关成员都是React内部规定的),基于这些属性描述出,我们所构建视图中的,DOM节点的相关特征!!

第一小步基于babel-preset-react-app 把JSX编译为React.createElement(…)这种格式!!

只要是元素节点,必然会基于createElement进行处理!
React.createElement(ele,props , . …children)
ele:元素标签名「或组件」
props:元素的属性集合(对象)「如果没有设置过任何的属性,则此值是null
children:第三个及以后的参数,都是当前元素的子节点

第二小步再把createElement方法执行,创建出virtua1DCN虚拟DOM对象「也有称之为:JSX元素、JSX对象、ReactChild对象…」!

virtualDOM= {
    $ $typeof : Symbol( react.element),
    ref: null,
    key: null,
    type:标签名「或组件」,
    //存储了元素的相关属性&&子节点信息
    props: {
    元素的相关属性,
    children:子节点信息「没有子节点则没有这个属性、属性值可能是一个值、也可能是一个数组」
   }
}

因为胡子语法({})无法直接创建对象,下面这样做是错误的:
在这里插入图片描述

所以我们可以通过React.createElement()来创建元素

在这里插入图片描述

总结:胡子语法中,不能之前嵌入除数组外的其他对象,但是有一个对象是可以直接嵌入的:JSX元素对象「虚拟DOM对象」

问题:胡子语法中不能直接渲染对象对不对??
不对,1.数组对象可以渲染,2.style的行内样式属性可以渲染,3.可以直接通过createElement来渲染!!


第二大步:渲染真实dom

真实DOM:浏览器页面中,最后渲染出来,让用户看见的DOM元素! !

v16

ReactDOM. render(
<>...</>,
document.getELementById( 'root')
);

v18

const root = ReactDOM.createRoot(document.getElementById('root')); 
root.render(
<>...</>
);

render方法实现!!!

首先封装一个对象迭代的方法,基于传统的for/in循环,会存在一些弊端 1.性能较差(既可以迭代私有的,也可以迭代公有的;2.只能迭代“可枚举、非Symbol类型的“属
性…

解决思路,获取对象的所有私有属性(无论是否枚举,无论是否可以枚举)

let keys = Object.getOwnPropertyNames(arr).concat(Object.getOwnPropertySymbols(arr));
console. log(keys);

或者使用es6的:
Reflect.ownKeys(arr);

封装的方法:each
在这里插入图片描述

说说往标签上加值:
在这里插入图片描述

export function render(virtualDOM, container) {
  let { type, props } = virtualDOM;
  if (typeof type === "string") {
    //存储的是标签名:动态创建这样一个标签
    let ele = document.createElement(type);
    //为标签设置相关的属性&子节点
    each(props, (value, key) => {
      // className的处理: value存储的是样式类名
      if(key === 'className') {
        ele.className = value;
        return;
      }
      // style的处理: va lue存储的是样式对象
      if (key === 'style') {
        each(value, (val, attr) => {
          ele.style[attr] = val;
        });
        return;
      }
      if (key === 'children') {
        let children =value;
        if(children.length===1) children =[children];
        children.forEach(child => {
          //子节点是文本节点:直接插入即可
          if(typeof child === "string") {
            ele.appendChild(document.createTextNode(child));
            return;
          }
          //子节点又是一个virtuaLDOM: 递归处理
          render(child, ele);
        });
        return;
      }
      ele.setAttribute(key, value);
    });
    container.appendChild(ele);
  }
};

//子节点的处理: value存储的children属性值

这段代码的作用是将一个虚拟 DOM 渲染到真实的 DOM 中。它首先会根据虚拟 DOM 中的 type 属性创建一个对应的 HTML 元素,然后根据虚拟 DOM 中的 props 属性设置元素的属性和子元素,最后将该元素插入到指定的 container 容器中。该代码也只考虑了样式类名和样式对象,而没有考虑其他可能出现的属性,例如 ID 属性、事件属性等。

补充说明:第1次渲染页面是直接从virtua LDOM- ->真实DOM;但是后期视图更新的时候,需要经过1个DOM-DIFF的对比,计算出补丁包PATCH(两次视图差异的部分),把PATCH补丁包进行渲染! !


函数组件的底层渲染机制!!

一.函数组件
1.创建:在SRC目录中,创建一个 xxx.jsx 的文件,就是要创建一个组件;我们在此文件中,创建一个函数,让函数返回JSX视图「或者JSX元素、virtualDOM虚拟DOM对象」;这就是创建了一个“函数组件”!!

2.调用:基于ES6Module规范,导入创建的组件「可以忽略.jsx后缀名」,然后像写标签一样调用这个组件即可!!
<Component/> 单闭合调用
<Component> ... </Component> 双闭合调用

命名:组件的名字,我们一般都采用PascalCase「大驼峰命名法」这种方式命名


二.调用组件的时候,我们可以给调用的组件设置(传递)各种各样的属性

<DemoOne title="我是标题" x={10} data={[100, 200]} className="box" style={{ fontSize: '20px' }} />
 1.如果设置的属性值不是字符串格式,需要基于“{}胡子语法”进行嵌套
 2.调用组件的时候,我们可以把一些数据/信息基于属性props的方式,传递给组件!!

这里是组件里面的代码:
在这里插入图片描述

这里是我们入口文件的代码:

在这里插入图片描述
那么这里的span是什么????

在这里插入图片描述
在第一张图的那个props里有一个children属性能够接收到这些东西!!!!!

单闭合调用和多闭合调用区别?
多闭合调用可以传入其他标签!!!!!!!!!单闭合不可以

渲染的机制:

渲染机制

1 基于babel-preset-react-app把调用的组件转换为createElement格式

React.createElement(DemoOne, {
            title: "u6211u662Fu6807u9898",
            x: 10,
            data: [100, 200],
            className: "box",
            style: {
                fontSize: '20px'
            }
        })

2 把createElement方法执行,创建出一个virtualDOM对象!!

{
            $$typeof: Symbol(react.element),
            key: null,
            props: {title: '我是标题', x: 10, data: 数组, className: 'box', style:{fontSize:'20px'}},//如果有子节点「双闭合调用」,则也包含children!!
            ref: null,
            type: DemoOne
}

3 基于root.render把virtualDOM变为真实的DOM,type值不再是一个字符串,而是一个函数了,此时:

    1.把函数执行 -> DemoOne()
    2.把virtualDOM中的props,作为实参传递给函数 -> DemoOne(props)
    3.接收函数执行的返回结果「也就是当前组件的virtualDOM对象」
    4.最后基于render把组件返回的虚拟DOM变为真实DOM,插入到#root容器中!!

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>