背景
我们平时习惯写react
,可能比较少的关注是怎么渲染的,比如你写了一个组件,这个组件是怎么被渲染成dom
元素显示的。
例子
const element = <h1 style={{color: 'red'}}>Hello, world</h1>;
ReactDOM.render(element, document.getElementById('root'));
babel
编译完以后生成一个react
节点对象
属性介绍
$$typeof
节点标识,简单说就是预防xss
漏洞,因为Symbol
无法被序列化【后端直接返回json给前端渲染】。
const ele = {
type: "div",
props: {
dangerouslySetInnerHTML: {
__html: '<img src="x" onerror="alert(1)">'
},
},
// $$typeof: Symbol.for('react.element'),
ref: null
}
ReactDOM.render(ele, document.getElementById('root'));
如果没有$$typeof
属性,会直接报错,运行效果如下:
现在直接加上
$$typeof
:
const ele = {
type: "div",
props: {
dangerouslySetInnerHTML: {
__html: '<img src="x" onerror="alert(1)">'
},
},
$$typeof: Symbol.for('react.element'),
ref: null
}
ReactDOM.render(ele, document.getElementById('root'));
运行效果如下:
key
react
节点唯一标识符,方便节点做diff
,并进行节点复用,减少不必要的dom
渲染,这里为null
是没有传key
的值,对于非list
节点,变动不大,可以直接进行逐层对比,官方并没有强制每一个元素都传key
,也是这个原因。
props
节点上包含的所有属性,包括字节点,方便后续渲染。
ref
在dom
元素上使用,就是为了获取当前的dom
元素
const inputRef = useRef();
<input ref={inputRef} /> // inputRef来访问input元素
在自定义组件上使用,获取相关的实力
type
节点类型,代表是h1
节点
完成渲染
react
的fiber
怎么进行diff等操作,节点怎么挂载,我们先忽略,直接通过虚拟dom
怎么生成元素
创建节点
function createElement (
type: string,
props: Object,
rootContainerElement: Element | Document,
parentNamespace: string) {
// ....
// type指的是h1节点
domElement = ownerDocument.createElement(type);
// ....
return domElement;
}
添加节点属性
function setInitialDOMProperties(
domElement: Element,
tag: string,
rawProps: Object,
rootContainerElement: Element | Document) {
// ...
// 设置dom属性
setInitialDOMProperties(
tag,
domElement,
rootContainerElement,
props,
isCustomComponentTag)
// ...
}
渲染成dom树
function appendChildToContainer(
container: Container,
child: Instance | TextInstance,) {
if (container.nodeType === COMMENT_NODE) {
parentNode = (container.parentNode: any);
parentNode.insertBefore(child, container);
} else {
parentNode = container;
parentNode.appendChild(child);
}
}
执行后 生成最终的dom
树