跳到主要内容

React

虚拟DOM

const element = <h1 class="hello">hello, world!</h1>
const component = <App />

上方的代码被称之为JSX语法,实际上会被编译成React.createElement,因此等价于以下代码

const element = React.createElement('h1', { class: 'hello' }, 'hello, world')
const component = React.createElement(App, null, null)

实际上React.createElement返回的是一个普通的对象,这种对象被称之为JSX.ElementReact.ReactElement,也可以被叫做虚拟DOM

const element = {
$$typeof: Symbol(react.element),
key: null,
props: {class: "hello", children: "hello, world!"},
ref: null,
type: "h1",
}

const component = {
$$typeof: Symbol(react.element),
key: null,
props: {},
ref: null,
type: App(), // 渲染函数
}

Fiber Node

备注

从上述代码中我们能了解到,虚拟DOM本身不存在指向其他虚拟DOM的指针,实际上除了我们最初传给ReactDOM.render的虚拟DOM,大多数虚拟DOM都是在渲染函数运行时动态生成的,通过在运行时递归调用渲染函数我们能够构建出一颗真正的树。

function App() {
return <Test />;
}

function Test() {
return <div>test</div>;
}

ReactDOM.render(<App />, document.getElementById('root'));

对于上方的代码,通过ReactDOM.render我们能够递归调用渲染函数,并且对于每一个组件实例(或者说虚拟DOM)我们都会创建一个Fiber Node,因为是运行时创建所以Fiber Node能够知道其所关联(parentchildsiblingFiber Node 是谁。

值得一提的是Hook所使用的memorizedState就是Fiber Node的一个属性。

警告

伪代码,主要用来表达FiberNode之间的连接关系

{
type: App(),
fiberNode: { // fiberNode1
child: fiberNode2,
return: null, // parent
memoizedState: {},
...rest,
}
}

{
type: Test(),
fiberNode: { // fiberNode2
child: fiberNode3,
return: fiberNode1
}
}

{
type: 'div',
fiberNode: { // fiberNode3
child: null,
return: fiberNode2,
}
}
总结

ReactDOM.render以我们传入的虚拟DOM为入口,递归调用渲染函数生成虚拟DOM,并且每个虚拟DOM都有对应的一个Fiber Node,这些Fiber Node通过地址形成了一颗完整的树。