【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)
  • 被设置不可扩展的对象:除了不能新增成员、其余的操作都可以处理!!
  • 被冻结的对象,即是不可扩展的,也是密封的!!同理,被密封的对象,也是不可扩展的!!
相关推荐
糕冷小美n3 小时前
elementuivue2表格不覆盖整个表格添加固定属性
前端·javascript·elementui
小哥不太逍遥3 小时前
Technical Report 2024
java·服务器·前端
沐墨染3 小时前
黑词分析与可疑对话挖掘组件的设计与实现
前端·elementui·数据挖掘·数据分析·vue·visual studio code
anOnion3 小时前
构建无障碍组件之Disclosure Pattern
前端·html·交互设计
threerocks3 小时前
前端将死,Agent 永生
前端·人工智能·ai编程
问道飞鱼4 小时前
【前端知识】Vite用法从入门到实战
前端·vite·项目构建
爱上妖精的尾巴4 小时前
8-10 WPS JSA 正则表达式:贪婪匹配
服务器·前端·javascript·正则表达式·wps·jsa
shadow fish5 小时前
react学习记录(三)
javascript·学习·react.js
小疙瘩5 小时前
element-ui 中 el-upload 多文件一次性上传的实现
javascript·vue.js·ui
Aliex_git5 小时前
浏览器 API 兼容性解决方案
前端·笔记·学习