初始化
jsx —经过babel转换—> createElement(创建vdom)——> render(vdom -> 真实dom)
更新
state/props改变 ——> update(diff…) ——> render(vdom -> 真实dom)

React渲染的过程实际上是由JSX创建React元素作为虚拟dom节点,调用render方法创建一棵虚拟dom树,然后映射到真实dom上由浏览器渲染出来。state和props改变时,会再次调用render生成一棵新的虚拟dom树,通过diff算法计算新旧两棵虚拟dom的差异,再异渲染到真实dom上

JSX

JSX是一个 JavaScript 的语法扩展,在HTML模板中嵌入JavaScript语法。由于React认为组件渲染逻辑与UI视图存在内在耦合,而JSX 可以很好地描述UI应该呈现出它应有交互的本质形式,所以React建议使用JSX语法。JSX完全可以实现JavaScript原有的功能。

JSX本质是React.createElement的语法糖,如下图例子所示,JSX会被Babel编译为createElement函数调用
image.png

createElement

实现转义后的jsx渲染到浏览器页面
挂载是递归过程

  1. function createElement(type, props, ...children) {
  2. return {
  3. type,
  4. props: {
  5. ...props,
  6. children: children.map((child) =>
  7. typeof child === "object" ? child : createTextElement(child)
  8. ),
  9. },
  10. };
  11. }
  12. function createTextElement(text) {
  13. return {
  14. type: "TEXT_ELEMENT",
  15. props: {
  16. nodeValue: text,
  17. children: [],
  18. },
  19. };
  20. }
  21. function render(element, container) {
  22. const dom =
  23. element.type == "TEXT_ELEMENT"
  24. ? document.createTextNode("")
  25. : document.createElement(element.type);
  26. const isProperty = (key) => key !== "children";
  27. Object.keys(element.props)
  28. .filter(isProperty)
  29. .forEach((name) => {
  30. dom[name] = element.props[name];
  31. });
  32. // 一旦我们开始渲染,我们不会停止,直到我们渲染了完整的元素树。
  33. // 如果元素树很大,可能会阻塞主线程太久。如果浏览器需要做高优先级的事情,
  34. // 比如处理用户输入或保持动画流畅,它必须等到渲染完成。
  35. element.props.children.forEach((child) => render(child, dom));
  36. container.appendChild(dom);
  37. }
  38. const Didact = {
  39. createElement,
  40. render,
  41. };
  42. // https://stackoverflow.com/questions/53803466/what-does-the-comment-jsx-jsx-do-in-the-emotion-css-in-js-library
  43. // 这是一个自定义 pragma,它告诉 jsx 转换器,在这种情况下,babel-plugin-transform-react 使用什么函数将您的 jsx 转换为纯 javascript。
  44. /** @jsx Didact.createElement */
  45. const element = (
  46. <div style="background: red">
  47. <h1>Hello World</h1>
  48. <h2 style="text-align:right">from Didact</h2>
  49. </div>
  50. );
  51. const el = document.getElementById("root");
  52. Didact.render(element, el);

存在问题
一旦我们开始渲染,我们不会停止,直到我们渲染了完整的元素树。如果元素树很大,可能会阻塞主线程太久。如果浏览器需要做高优先级的事情,比如处理用户输入或保持动画流畅,它必须等到渲染完成。

react完整的createElement

image.png

  • $$typeof属性用于检测节点是否为合法的React元素
  • type属性即节点类型
  • key用作节点的唯一标识
  • ref用于获取真实的dom节点
  • props包含了节点的默认属性和用户给它定义的属性以及子节点
  • _owner标识该节点隶属于哪个组件

https://segmentfault.com/a/1190000023356625