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

jsx通过babel转译成React.createElement创建虚拟DOM。虚拟DOM通过ReactDOM.render转化为真实DOM。函数组件调用时,属性通过props传递,内部通过执行函数生成新的虚拟DOM并渲染。单闭合调用不包含子元素,双闭合可以。渲染过程包括虚拟DOMdiff和应用patch。
摘要由CSDN通过智能技术生成

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: "\u6211\u662F\u6807\u9898",
            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容器中!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 如果你想要在父组件中控制子组件渲染,可以使用 React 的条件渲染功能,即根据某个条件来决定是否渲染组件。 以下是一个示例代码: ```jsx import React, { useState } from 'react'; function ParentComponent() { const [shouldRenderChild, setShouldRenderChild] = useState(true); function handleButtonClick() { // 点击按钮时,切换 shouldRenderChild 的值 setShouldRenderChild(!shouldRenderChild); } return ( <div> <button onClick={handleButtonClick}>Toggle child component</button> {shouldRenderChild && <ChildComponent />} </div> ); } function ChildComponent() { return <div>Child component</div>; } ``` 在上面的示例中,`ParentComponent` 组件中定义了一个名为 `shouldRenderChild` 的状态变量,初始值为 `true`,表示要渲染组件。在 `ParentComponent` 组件中,可以在需要渲染组件的地方使用条件渲染来控制子组件渲染。在上面的代码中,我们使用了 `shouldRenderChild && <ChildComponent />` 的语法来实现子组件的条件渲染,当 `shouldRenderChild` 为 `true` 时,渲染 `ChildComponent` 组件,否则不渲染。 在 `handleButtonClick` 函数中,调用 `setShouldRenderChild` 来切换 `shouldRenderChild` 的值,从而实现在父组件中阻止子组件渲染。 需要注意的是,在使用条件渲染时,如果要渲染的子组件比较复杂,可以将子组件渲染逻辑单独提取到一个函数中,以提高代码的可读性和可维护性。 ### 回答2: 在 React 中,父组件主要通过向子组件传递 props 来控制子组件渲染。如果我们希望在父组件中阻止子组件渲染,有几种方法可以实现。 一种简单的方法是通过在父组件的 render 方法中根据一定的条件来控制下一级子组件渲染。比如,我们可以在父组件中定义一个变量,根据这个变量的值动态决定是否渲染组件。示例如下: ```javascript class ParentComponent extends React.Component { render() { const shouldRenderChild = false; // 根据条件决定是否渲染组件 return ( <div> {shouldRenderChild && <ChildComponent />} // 根据条件渲染组件 </div> ); } } ``` 在上面的示例中,如果 shouldRenderChild 的值为 true,那么子组件 ChildComponent 就会被渲染到父组件中,否则不会被渲染。 另一种方法是使用 React 的生命周期方法 shouldComponentUpdate。我们可以在父组件中重写这个方法,在其中根据一定的条件返回 true 或 false,来决定子组件是否需要重新渲染。示例如下: ```javascript class ParentComponent extends React.Component { shouldComponentUpdate(nextProps, nextState) { const shouldRenderChild = false; // 根据条件决定是否渲染组件 return shouldRenderChild; // 返回 true 或 false } render() { return ( <div> <ChildComponent /> </div> ); } } ``` 在这种情况下,如果 shouldRenderChild 的值为 true,则子组件 ChildComponent 会重新渲染;如果值为 false,则子组件不会重新渲染。 总结来说,父组件可以通过在 render 方法中根据条件决定是否渲染组件,或者重写 shouldComponentUpdate 方法来控制子组件渲染。这些方法可以根据具体的业务需求来选择合适的方式来实现。 ### 回答3: 在React中,如果希望在父函数组件中阻止子组件渲染,可以使用React的shouldComponentUpdate()方法或者React的memo()函数来实现。 对于使用class组件的父函数组件,可以重写shouldComponentUpdate()方法,该方法决定了组件在是否需要重新渲染。在shouldComponentUpdate()方法中,可以通过判断父组件的某个状态或属性是否发生变化,来决定是否进行重新渲染。如果需要阻止子组件渲染,可以在shouldComponentUpdate()返回false。这样,子组件就不会因为父组件的更新而重新渲染。 对于使用函数组件的父函数组件,可以使用React的memo()函数来包裹子组件。memo()函数是一个高阶组件,能够阻止子组件的不必要的重新渲染。当以memo()包裹的子组件的props没有变化时,子组件就不会重新渲染。 无论是使用shouldComponentUpdate()方法还是memo()函数,都需要谨慎使用,以免过多的阻止组件的重新渲染带来性能问题。只有在确实需要减少不必要的重新渲染时,才应该使用这些方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值