【React】函数组件底层渲染机制

目录

函数组件

创建

创建一个函数,让函数返回JSX视图「或者JSX元素、virtualDOM虚拟DOM对象」,就是创建了一个"函数组件"。

javascript 复制代码
const DemoOne = function DemoOne(props) {
    return <div className="demo-box">
        <h2 className="title">Hello,world</h2>
    </div>;
}; 

调用&命名

基于ES6Module规范,导入创建的组件「可以忽略.jsx后缀名」,然后像写标签一样调用这个组件即可。组件的名字,一般都采用PascalCase「大驼峰命名法」这种方式命名。

javascript 复制代码
<Component/> 单闭合调用
<Component> ... </Component> 双闭合调用
javascript 复制代码
import DemoOne from './views/DemoOne';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <DemoOne />
)

组件传参

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

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

打印子组件接收到的参数:

javascript 复制代码
const DemoOne = function DemoOne(props) {
    console.log(props,'props')
    const {title,x,data,style,className} = props;
    return <div className="demo-box">
    <h2 className="title">Hello,world</h2>
</div>;
};

渲染机制

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

javascript 复制代码
<DemoOne title="我是标题" x={10} data={[100, 200]} className="box" style={{ fontSize: '20px' }} />

上面JSX语法经过babel-preset-react-app编译为如下:

javascript 复制代码
import { jsx as _jsx } from "react/jsx-runtime";
createElement(DemoOne, {
  title: "\u6211\u662F\u6807\u9898",
  x: 10,
  data: [100, 200],
  className: "box",
  style: {
    fontSize: '20px'
  }
});

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

javascript 复制代码
     {
            $$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 值不再是一个字符串,而是一个函数,此时:

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

对属性props的处理

调用组件,传进来的props是可读的,不可修改,可以通过Object.isFrozen(props) 进行判断:

javascript 复制代码
const DemoOne = function DemoOne(props) {
    console.log(Object.isFrozen(props)) //结果为true,说明props传进来被冻结了;
    const {title,x,data,style,className} = props;
    return <div className="demo-box">
    <h2 className="title">Hello,world</h2>
</div>;

如果修改props中的值就会报错,如下:

javascript 复制代码
const DemoOne = function DemoOne(props) {
    props.title = "你好";
    return <div className="demo-box">
    <h2 className="title">{title}</h2>
</div>;
};

虽然对于传递进来的属性,我们不能直接修改,但是可以做一些规则校验

  • 设置默认值
javascript 复制代码
DemoOne.defaultProps = {
    x: 0
};
  • 设置参数类型,需要用到prop-types插件, https://github.com/facebook/prop-types,传递进来的属性,首先会经历规则的校验,不管校验成功还是失败,最后都会把属性给形参props,只不过如果不符合设定的规则,控制台会抛出警告错误(不影响属性值的获取)
javascript 复制代码
import PropTypes from 'prop-types';
函数组件.propTypes = {
        // 类型是字符串、必传
        title: PropTypes.string.isRequired,
        // 类型是数字
        x: PropTypes.number,
        // 多种校验规则中的一个
        y: PropTypes.oneOfType([
            PropTypes.number,
            PropTypes.bool,
        ])
      };

如果想把传递的属性值进行修改,可以:

  • 把props中的某个属性赋值给其他内容「例如:变量、状态...」
  • 我们不直接操作props.xxx=xxx,但是我们可以修改变量/状态值
javascript 复制代码
const DemoOne = function DemoOne(props) {
    console.log(props, 'props')
    let { title, x, data, style, className } = props;
    return <div className="demo-box">
        <h2 className="title">{title}</h2>
    </div>;
};

关于对象的规则设置

冻结

  • 冻结对象:Object.freeze(obj)
  • 检测是否被冻结:Object.isFrozen(obj) =>true/false
  • 被冻结的对象:不能修改成员值、不能新增成员、不能删除现有成员、不能给成员做劫持「Object.defineProperty」

密封

  • 密封对象:Object.seal(obj)
  • 检测是否被密封:Object.isSealed(obj)
  • 被密封的对象:可以修改成员的值,但也不能删、不能新增、不能劫持!!

扩展

  • 把对象设置为不可扩展:Object.preventExtensions(obj)
  • 检测是否可扩展:Object.isExtensible(obj)
  • 被设置不可扩展的对象:除了不能新增成员、其余的操作都可以处理!!
  • 被冻结的对象,即是不可扩展的,也是密封的!!同理,被密封的对象,也是不可扩展的!!
相关推荐
卸任5 小时前
Vibe coding工具使用心得
前端·ai编程
brien96 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance6 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M6 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写6 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李6 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易7 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
清晨Coding7 小时前
删了 Cookie 还能自动登录?Google系网站登录态自动恢复的原理分析
javascript
风骏时光牛马7 小时前
前沿视界
前端
kyriewen7 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员