createElement

  1. export function createElement(type, config, children) {
  2. let propName;
  3. // Reserved names are extracted
  4. const props = {};
  5. let key = null;
  6. let ref = null;
  7. let self = null;
  8. let source = null;
  9. // 如果元素有属性
  10. if (config != null) {
  11. // 验证是否有 Ref prop,如果有则取出
  12. if (hasValidRef(config)) {
  13. ref = config.ref;
  14. }
  15. // 验证是否有 Key prop,如果有则取出,同时字符串化
  16. if (hasValidKey(config)) {
  17. key = '' + config.key;
  18. }
  19. // 用于测试、debug、准确抛出错误用的信息
  20. self = config.__self === undefined ? null : config.__self;
  21. source = config.__source === undefined ? null : config.__source;
  22. // 遍历 props,如果存在,并且并不与内部 props 冲突则合并到变量 props 中
  23. // 简而言之,提取有用且有效的 props
  24. for (propName in config) {
  25. if (
  26. hasOwnProperty.call(config, propName) &&
  27. !RESERVED_PROPS.hasOwnProperty(propName)
  28. ) {
  29. props[propName] = config[propName];
  30. }
  31. }
  32. }
  33. // Children can be more than one argument, and those are transferred onto
  34. // the newly allocated props object.
  35. // 第三个参数开始,后面的参数都可以是 children,所以后面的参数有多少决定了 children 有多少
  36. const childrenLength = arguments.length - 2;
  37. // 如果只有一个,则直接赋值
  38. if (childrenLength === 1) {
  39. props.children = children;
  40. } else if (childrenLength > 1) {
  41. // 遍历入参,传到一个数组中,赋值到 children 中
  42. const childArray = Array(childrenLength);
  43. for (let i = 0; i < childrenLength; i++) {
  44. childArray[i] = arguments[i + 2];
  45. }
  46. props.children = childArray;
  47. }
  48. // 合并默认 props
  49. if (type && type.defaultProps) {
  50. const defaultProps = type.defaultProps;
  51. for (propName in defaultProps) {
  52. if (props[propName] === undefined) {
  53. props[propName] = defaultProps[propName];
  54. }
  55. }
  56. }
  57. // 工厂函数生成元素结构
  58. return ReactElement(
  59. type,
  60. key,
  61. ref,
  62. self,
  63. source,
  64. ReactCurrentOwner.current,
  65. props,
  66. );
  67. }

ReactElement

  1. const ReactElement = function(type, key, ref, self, source, owner, props) {
  2. const element = {
  3. // This tag allows us to uniquely identify this as a React Element
  4. // 独一无二的表示,用于确认当前的元素是 react 的元素
  5. $$typeof: REACT_ELEMENT_TYPE,
  6. // Built-in properties that belong on the element
  7. // 当前元素的构造函数或者生成函数或者标签名称
  8. type: type,
  9. key: key,
  10. ref: ref,
  11. props: props,
  12. // Record the component responsible for creating this element.
  13. // ReactCurrentOwner是一个对象,只有current一个属性,用于存储当前正在构建的Component所属的Component。
  14. // ReactCurrentOwner.current主要在 react-dom 的ReactCompositeComponent中被赋值。
  15. _owner: owner,
  16. };
  17. return element;
  18. };

createFactory

  1. // 用于生成快速生成某个组件的工厂函数的函数(真绕啊,汗
  2. export function createFactory(type) {
  3. const factory = createElement.bind(null, type);
  4. // Expose the type on the factory and the prototype so that it can be
  5. // easily accessed on elements. E.g. `<Foo />.type === Foo`.
  6. // This should not be named `constructor` since this may not be the function
  7. // that created the element, and it may not even be a constructor.
  8. // Legacy hook: remove it
  9. factory.type = type;
  10. return factory;
  11. }

cloneAndReplaceKey

  1. // 克隆一个元素并重置其 key 值
  2. export function cloneAndReplaceKey(oldElement, newKey) {
  3. const newElement = ReactElement(
  4. oldElement.type,
  5. newKey,
  6. oldElement.ref,
  7. oldElement._self,
  8. oldElement._source,
  9. oldElement._owner,
  10. oldElement.props,
  11. );
  12. return newElement;
  13. }

cloneElement

  1. export function cloneElement(element, config, children) {
  2. // 类型校验
  3. invariant(
  4. !(element === null || element === undefined),
  5. 'React.cloneElement(...): The argument must be a React element, but you passed %s.',
  6. element,
  7. );
  8. let propName;
  9. // 浅拷贝被拷贝的元素的 props
  10. const props = Object.assign({}, element.props);
  11. // 获取被拷贝元素的 key,ref,_self,_source,_owner
  12. // Reserved names are extracted
  13. let key = element.key;
  14. let ref = element.ref;
  15. // Self is preserved since the owner is preserved.
  16. const self = element._self;
  17. // Source is preserved since cloneElement is unlikely to be targeted by a
  18. // transpiler, and the original source is probably a better indicator of the
  19. // true owner.
  20. const source = element._source;
  21. // Owner will be preserved, unless ref is overridden
  22. let owner = element._owner;
  23. // 获取新的元素配置,并覆盖被克隆元素传递下来的值
  24. if (config != null) {
  25. if (hasValidRef(config)) {
  26. // Silently steal the ref from the parent.
  27. ref = config.ref;
  28. owner = ReactCurrentOwner.current;
  29. }
  30. if (hasValidKey(config)) {
  31. key = '' + config.key;
  32. }
  33. // Remaining properties override existing props
  34. let defaultProps;
  35. if (element.type && element.type.defaultProps) {
  36. defaultProps = element.type.defaultProps;
  37. }
  38. for (propName in config) {
  39. if (
  40. hasOwnProperty.call(config, propName) &&
  41. !RESERVED_PROPS.hasOwnProperty(propName)
  42. ) {
  43. if (config[propName] === undefined && defaultProps !== undefined) {
  44. // Resolve default props
  45. props[propName] = defaultProps[propName];
  46. } else {
  47. props[propName] = config[propName];
  48. }
  49. }
  50. }
  51. }
  52. // Children can be more than one argument, and those are transferred onto
  53. // the newly allocated props object.
  54. const childrenLength = arguments.length - 2;
  55. if (childrenLength === 1) {
  56. props.children = children;
  57. } else if (childrenLength > 1) {
  58. const childArray = Array(childrenLength);
  59. for (let i = 0; i < childrenLength; i++) {
  60. childArray[i] = arguments[i + 2];
  61. }
  62. props.children = childArray;
  63. }
  64. // 创建元素对象
  65. return ReactElement(element.type, key, ref, self, source, owner, props);
  66. }

isValidElement

  1. // 通过元素的 $$typeof 判断该元素是不是 React 元素
  2. export function isValidElement(object) {
  3. return (
  4. typeof object === 'object' &&
  5. object !== null &&
  6. object.$$typeof === REACT_ELEMENT_TYPE
  7. );
  8. }