深刻react-基礎API(三)

前言

繼續上一篇,還有4個API:
createElement,
cloneElement
createFactory
isValidElementreact

createElement

<div className="class" props="props" ref="ref" key="key">
    <p>1</p>
    <p>2</p>
  </div>,

上面這段jsx代碼經過babel轉換後以下babel

React.createElement("div", {
  className: "class",
  props: "props",
  ref: "ref",
  key: "key"
}, React.createElement("p", null, "1"), React.createElement("p", null, "2"));
  • 能夠看到轉換後會調用createElement函數
  • 第一個參數是個domElement 字符串
  • 第二個參數是個把標籤上的屬性轉換成了一個對象
  • 後面的參數也是createElement函數,分別是兩個包裹在div中的p標籤的建立,也就是children
// 不加入到props對象中的屬性
const RESERVED_PROPS = {
  key: true,
  ref: true,
  __self: true,
  __source: true
};

export function createElement(type, config, ...children) {
  let propName;
  const props = {};
  let key = null;
  let ref = null;

  if (config !== null) {
    key = config.key || null;
    ref = config.ref || null;
  }

  if (config != null) {
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }

  // default props, 好比class App上掛了 App.defaultProps = {} 時的處理
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (!props[propName]) {
        props[propName] = defaultProps[propName];
      }
    }
  }

  // react-dom 首次渲染 沒有children參數
  props.children =
    children.length === 0
      ? null
      : children.length === 1
      ? children[0]
      : children;

  return ReactElement(type, key, ref, props);
}
  • 拿到config中的key和ref分別賦值給聲明好的key和ref
  • 遍歷config中的屬性,根據RESERVED_PROPS對象過濾不須要的屬性,將剩下的屬性所有保存到props這個對象中
  • 將default中的屬性拷貝到props中
  • 保存children到props中
  • 調用ReactElement
const ReactElement = (type, key, ref, props) => {
  const element = {
    $$typeof: REACT_ELEMENT_TYPE,
    type,
    ref,
    key,
    props: props
  };

  return element;
};
  • 返回一個element對象
  • `$$`typeof: 一個symbol標識,標識是什麼類型的element,和前面的一些API裏的稍有不通,前面一些API中的$$typeof是保存在type當中
  • type:createElement的第二個參數
  • ref:在createElement中提取的ref
  • key:在createElement中提取的key
  • props:在createElement中處理後的props

cloneElement

export function cloneElement(element, config, ...children) {
  let propName;

  const props = Object.assign({}, element.props);

  let key = element.key;
  let ref = element.ref;

  if (config != null) {
    if (config.ref !== undefined) {
      ref = config.ref;
    }
    if (config.key !== undefined) {
      key = "" + config.key;
    }

    let defaultProps;
    if (element.type && element.type.defaultProps) {
      defaultProps = element.type.defaultProps;
    }
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        if (config[propName] === undefined && defaultProps !== undefined) {
          // Resolve default props
          props[propName] = defaultProps[propName];
        } else {
          props[propName] = config[propName];
        }
      }
    }

    props.children =
      children.length === 0
        ? null
        : children.length === 1
        ? children[0]
        : children;

    return ReactElement(element.type, key, ref, props);
  }
}

cloneElement的實現和createElement幾乎同樣,最後return的仍是一個ReactElement對象,只不過第一個參數不一樣,第一個參數接收的是一個ReactElement,也就是createElement返回的那個對象dom

createFactory

export function createFactory(type) {
  const factory = createElement.bind(null, type);
  factory.type = type;

  return factory;
}
  • 返回一個createElement(type) 函數

這個API好像已經沒用了,也用不到函數

isValidElement

/**
 * 驗證是不是react對象,主要是經過對象上的$$typeof屬性
 * @param {*} object
 */
export function isValidElement(object) {
  return (
    typeof object === "object" &&
    object !== null &&
    object.$$typeof === REACT_ELEMENT_TYPE
  );
}
  • 一個驗證是不是react對象的函數,主要是經過對象上的$$typeof屬性

react這個包基本寫完了code

相關文章
相關標籤/搜索