1. react组件如何通过jsx解析为js
jsx解析的过程:通过插件babel-preset-set,将jsx解析为js,示例:
const p = <p className="test">i am {name}</p>
jsx语言通过jsx-runtime解析转化,最终得到下面的一个对象
import {jsx as _jsxs} from 'react/jsx-runtime'
const p = _jsxp('p',{
className:'aa',
children:['i am',name]
})
最终源码得到的对象<虚拟dom>如下,通过对象表达语法树
function createElement(type,props,...children){
return{
type,
props: {
...props,
children
}
}
}
2. 手写render:将虚拟DOM渲染到对应节点上
ReactDOM.render(<APP />,document.getElementById('root'))
function render(vDom,container){
let dom;
//检查当前节点是文本还是对象
if(typeof vDom !== 'object') {
dom=document.createTextNode(vDom)
}else{
dom=document.createElement(vDom.type)
}
// 将vDom上除了children外的属性都挂载到真正的DOM上去
// <p className='aa'></p>
if(vDom.props){
Object.keys(vDom.props).filter(key => key != 'chilren').forEach(item => dom[item] = vDom.props[item])
}
// 如果还有子元素,递归调用
if(vDom.props && vDom.props.children && vDom.props.children.length){
vDom.props.children.forEach(child => render(child,dom))
}
container.appendChild(dom)
}
3. 为什么使用fiber
fiber通俗的理解是见缝插针的执行js,在fiber出现之前,diff算法计算虚拟VDOM -> create DOM 是同步执行的,而且js执行机制是单线程,如果执行时间很长,执行js时不渲染页面会出现卡顿;
fiber则良好的解决了这个问题,所以也是react性能提升的重要一环
(1). 同步不可中断 -> 异步可中断(新的数据结构,中断之后返回可以继续执行)
(2). scheduler任务的优先级
fiber的数据结构是一棵树,包含3部分:
(1). child:父节点指向第一个子元素的指针;
(2). subling:从第一个元素往后,指向下一个兄弟元素
(3). return:所有子元素都有的指向父元素的指针
通过树节点的数据结构,可以遍历所有节点,将所有节点任务生成任务列表,执行时中断其中的某个任务,也可以通过节点继续执行。
以如下代码 示例:
<div>
<p>
<span></span>
<text></text>
</p>
</div>
fiber遍历遵循深度遍历优先(先找子元素,子元素没有了找兄弟元素,都没有返回父元素,然后再找父元素的兄弟元素..)
所以 上述遍历路径为:div -> p:child -> span:child -> sibling -> text -> return