我们写的jsx语法,经过babel等的编译,会变成render函数(为什么不直接把 jsx 编译为 vdom 呢?因为 render function 可以执行动态逻辑呀。我们可以加入 state、props,也可以包装一下实现组件),render函数的执行结果就是vdom, 也就是React Element的实例;
在 16 之前,React 是直接递归渲染 vdom 的,setState 会触发重新渲染,对比渲染出的新旧 vdom,对差异部分进行 dom 操作。
在 16 之后,为了优化性能,会先把 vdom 转换成 fiber,也就是从树转换成链表,然后再渲染。整体渲染流程分成了两个阶段:
- render 阶段:从 vdom 转换成 fiber,并且对需要 dom 操作的节点打上 effectTag 的标记
- commit 阶段:对有 effectTag 标记的 fiber 节点进行 dom 操作,并执行所有的 effect 副作用函数。
从 vdom 转成 fiber 的过程叫做 reconcile(调和),这个过程是可以打断的,由 scheduler 调度执行。
react 把 commit 阶段也分成了 3 个小阶段:
- before mutation:会异步调度 useEffect 的回调函数
- mutation:就是遍历 effectList 来更新 dom
- layout:会同步调用 useLayoutEffect 的回调函数,而且这个阶段可以拿到新的 dom 节点