React深入学习笔记
2023-08-19 本文已影响0人
Mstian
好久没有再好好静心学习了,总是感觉很忙碌,很疲惫,现在准备开始重新学习记录,先从学习React开始吧,学习理论,慢慢更新笔记,会整体的更新完整个React体系学习记录,看到这篇文章的有缘人,如果你也在学习或者有疑问,或者我学习记录中有错误,欢迎一起进步。
关于JSX底层处理机制
1、将JSX语法编写代码转换成虚拟对象(Virtual Dom)
基于babel-preset-react-app 把JSX转换为React.createElement()方法;
只要是元素节点,必然会基于该方法处理;
React.createElement(ele, props, ...children);
+ ele - 元素标签名
+ props - 元素的属性集合(如果没有设置过属性,该值为null)
+ children - 第三个以及以后的参数,表示当前元素的子节点
再通过执行React.createElement方法创建出虚拟对象(vdom);
vdom = {
$$typeof: Symbol(react.element),
ref: null,
key: null,
type: 标签名(或组件),
props: {
元素相关属性,
children: 子节点信息(没有子节点,没有这个属性,属性可能是一个值,也可能是一个数组)
}
}
实现React.createElement方法:
function createElement(ele, props, ...children){
const virtualDOM = {
$$typeof: Symbol('react.element'),
ref: null,
key: null,
type: null,
props: {}
};
virtualDOM.type = ele;
if (props != null) {
virtualDOM.props = {
...props,
}
}
if (children.length === 1) virtualDOM.props.children = children[0];
if (children.length > 1) virtualDOM.props.children = children;
return virtualDOM;
}
2、把构建的虚拟DOM转换成真实DOM
基于ReactDOM中render方法处理;
注意这里React16 和 React18语法有所不同
V16
ReactDOM.render(<App/>, document.getElementById('root'))
V18
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
实现render方法:
render方法本质就是遍历虚拟dom对象,如果有子节点那么久递归,然后生成真实dom最终插入到文档。
首先实现一个可以遍历对象所有私有属性的方法(私有的,不论是否可枚举,不论类型)
Object.getOwnPropertyNames(arr); 获取对象非Symbol类私有属性(无论是否可枚举)
Object.getOwnPropertySymbols(arr);获取对象Symbole类私有属性
还可以使用ES6提供Reflect.ownKeys(obj); 直接获取对象所有私有属性方法。
function each(obj, callback) {
// 一个好的函数一定会优先处理边界异常
if (obj == null || typeof obj !=='object') {
throw new TypeError('obj is not an object');
}
if (typeof callback !== 'function') {
throw new TypeError('callback is not a function')
}
const keys = Reflect.ownKeys(obj);
keys.forEach((key, index) => {
callback(obj[key], key);
})
}
todo:学习Reflect
const virtualDOM = {
$$typeof: Symbol('react.element'),
ref: null,
key: null,
type: null,
props: {}
};
function render(vdom, container) {
const {type, props} = vdom;
if (typeof type === 'string') {
const ele = document.createElement(type);
each(props, (value, key) => {
if (key === 'className') {
ele.className = value;
return;
}
if (key === 'style') {
each(value, (attrV, attrK) => {
ele.style[attrK] = attrV;
})
return;
}
if (key === 'children') {
let children = value;
if (!Array.isArray(children)) {
children = [children]
}
each(children, (child) => {
if (/^(string | number)$/.test(child)) {
ele.appendChild(document.createTextNode(child));
}
render(child, ele);
})
return;
}
ele.setAttribute(key, value);
})
container.append(ele);
}
}