微信截图_20210410213911.png
CgqCHl-BegWAbxNEAAH9HxafvWE988.png

JSX 映射为 DOM

JSX.png

createElement 源码

  1. /**
  2. 101. React的创建元素方法
  3. */
  4. export function createElement(type, config, children) {
  5. // propName 变量用于储存后面需要用到的元素属性
  6. let propName;
  7. // props 变量用于储存元素属性的键值对集合
  8. const props = {};
  9. // key、ref、self、source 均为 React 元素的属性,此处不必深究
  10. let key = null;
  11. let ref = null;
  12. let self = null;
  13. let source = null;
  14. // config 对象中存储的是元素的属性
  15. if (config != null) {
  16. // 进来之后做的第一件事,是依次对 ref、key、self 和 source 属性赋值
  17. if (hasValidRef(config)) {
  18. ref = config.ref;
  19. }
  20. // 此处将 key 值字符串化
  21. if (hasValidKey(config)) {
  22. key = '' + config.key;
  23. }
  24. self = config.__self === undefined ? null : config.__self;
  25. source = config.__source === undefined ? null : config.__source;
  26. // 接着就是要把 config 里面的属性都一个一个挪到 props 这个之前声明好的对象里面
  27. for (propName in config) {
  28. if (
  29. // 筛选出可以提进 props 对象里的属性
  30. hasOwnProperty.call(config, propName) &&
  31. !RESERVED_PROPS.hasOwnProperty(propName)
  32. ) {
  33. props[propName] = config[propName];
  34. }
  35. }
  36. }
  37. // childrenLength 指的是当前元素的子元素的个数,减去的 2 是 type 和 config 两个参数占用的长度
  38. const childrenLength = arguments.length - 2;
  39. // 如果抛去type和config,就只剩下一个参数,一般意味着文本节点出现了
  40. if (childrenLength === 1) {
  41. // 直接把这个参数的值赋给props.children
  42. props.children = children;
  43. // 处理嵌套多个子元素的情况
  44. } else if (childrenLength > 1) {
  45. // 声明一个子元素数组
  46. const childArray = Array(childrenLength);
  47. // 把子元素推进数组里
  48. for (let i = 0; i < childrenLength; i++) {
  49. childArray[i] = arguments[i + 2];
  50. }
  51. // 最后把这个数组赋值给props.children
  52. props.children = childArray;
  53. }
  54. // 处理 defaultProps
  55. if (type && type.defaultProps) {
  56. const defaultProps = type.defaultProps;
  57. for (propName in defaultProps) {
  58. if (props[propName] === undefined) {
  59. props[propName] = defaultProps[propName];
  60. }
  61. }
  62. }
  63. // 最后返回一个调用ReactElement执行方法,并传入刚才处理过的参数
  64. return ReactElement(
  65. type,
  66. key,
  67. ref,
  68. self,
  69. source,
  70. ReactCurrentOwner.current,
  71. props,
  72. );
  73. }
  • type:标记节点的类型
  • config:对象形式,关于组件的所有的属性
  • children:对象形式,嵌套的子组件 ```typescript
    • 1
    • 2

React.createElement(“ul”, { // 传入属性键值对 className: “list” // 从第三个入参开始往后,传入的参数都是 children }, React.createElement(“li”, { key: “1” }, “1”), React.createElement(“li”, { key: “2” }, “2”));

  1. <a name="48olP"></a>
  2. ## ReactElement ->> 虚拟 DOM
  3. ```typescript
  4. const ReactElement = function(type, key, ref, self, source, owner, props) {
  5. const element = {
  6. // REACT_ELEMENT_TYPE是一个常量,用来标识该对象是一个ReactElement
  7. $$typeof: REACT_ELEMENT_TYPE,
  8. // 内置属性赋值
  9. type: type,
  10. key: key,
  11. ref: ref,
  12. props: props,
  13. // 记录创造该元素的组件
  14. _owner: owner,
  15. };
  16. //
  17. if (__DEV__) {
  18. // 这里是一些针对 __DEV__ 环境下的处理,对于大家理解主要逻辑意义不大,此处我直接省略掉,以免混淆视听
  19. }
  20. return element;
  21. };

Ciqc1F-BezKAW4rXAAIUYQW6Lk0911.png

参考资料

  1. 02 | 为什么 React 要用 JSX?
  2. 01 | JSX 代码是如何“摇身一变”成为 DOM 的?