JSX底层渲染机制:
函数组件渲染机制:
JSX底层原理:
// 1. 基于babel-preset-react-app语法包将jsx语法编译为React.createElement()格式
// 2. 执行createElement方法,创建虚拟dom
// 在react中<>> 为React.Fragement 空文本标记标签
// 传参格式:(ele,props,...children)
// ele:元素标签,组件名
// props:元素属性集合,如果不设置为null,
// children:第三个及以后的元素为当前元素的子节点
React.createElement(
React.Fragement,
null,
React.createElement('h2',{className:'title'},'\u73E0'),
React.createElement(
'div',
{className:'box'},
React.createElement('span',null,x),
),
)
// 使用jsx文件处理生成dom对象,createElement原理
function createElement(ele,props,...children){
const virtualDOM = {
$$typeof:Symbol('react.element'),
key:null,
ref:null,
type:null,
props:{}
}
// 定义传进来的children长度为length
let length = children.length
// 将ele赋值给virtualDOM.type
virtualDOM.type = ele
// 判断props是否为null
if(props!==null){
virtualDOM.props = [...props]
if(length === 1){
virtualDOM.props.children = children[0]
}
if(length > 1){
virtualDOM.props.children = children
}
}
return virtualDOM
}
// 封装基于迭代的对象方法
const each = function each(obj,callback){
if(obj ===null || typeof obj !=='object'){
throw new TypeError('obj is not object')
}
if(typeof callback !== 'function'){
throw new TypeError('callback is not function')
}
// Reflect.ownkeys(obj)返回一个由目标对象自身的可枚举属性键(不包括原型链上的属性)组成的数组。
let keys = Reflect.ownkeys(obj)
keys.forEach((i)={
let val = obj[i]
// 每次迭代调用回调函数并执行
callback(val,i)
})
}
// 虚拟dom变为真实dom
function render(virtualDOM){
let { type, props } = virtualDOM
if(typeof type==='string'){
// 存储的是标签名,动态创建标签
let ele = document.createElement(type)
// 遍历props,为标签设置相关属性/子节点,
each(props, (value,key)=>{
// className处理,定义类名
if(key==='className'){
ele.className = value
return;
}
// style处理,样式对象
if(key==='style'){
each(value,(value,attr)=>{
ele.style[attr] = value
})
return;
}
if(key==='children'){
// 判断是否为数组,如果不是数组时为字符串
if(!Array.isArray(children)) children = [value]
value.forEach((child)=>{
if(typeof child==='string'){
ele.appendChild(document.createTextNode(child))
return;
}
// 子节点是v-dom,递归处理
render(child,ele)
})
return;
}
ele.setAttribute(key,value)
})
// 将新增的标签添加到指定容器中,this指向root容器
this.appendChild(ele)
}
}
// v16版本
ReactDOM.render(
<div className='container'>
<h1>哈哈哈哈哈</h1>
</div>,
document.getElementById('root')
)
// v18版本
import { createRoot } from 'react-dom/client'
const container = document.getElementById('root') as HTMLElement
const root = createRoot(container)
root.render(
<div className='container'>
<h1>哈哈哈哈哈</h1>
</div>
)