源码的文件结构https://react.iamkasong.com/preparation/file.html

packages目录(了解)

react(opens new window)文件夹

React的核心,包含所有全局 React API,如:

  • React.createElement
  • React.Component
  • React.Children

    #scheduler(opens new window)文件夹

    Scheduler(调度器)的实现。

    #shared(opens new window)文件夹

    源码中其他模块公用的方法全局变量,比如在shared/ReactSymbols.js(opens new window)中保存React不同组件类型的定义。

    Renderer相关的文件夹

    调试源码

    https://react.iamkasong.com/preparation/source.html#%E6%8B%89%E5%8F%96%E6%BA%90%E7%A0%81

    深入理解JSX!

    1. // 编译前
    2. <p>KaSong</p>
    3. // 编译后
    4. h("p", null, "KaSong");

    React.createElement:jsx会被编译为React.createElement

    在React中,所有JSX在运行时的返回结果,即(React.createElement()的返回值)都是ReactElement。 ```javascript export function createElement(type, config, children) { let propName;

    // Reserved names are extracted const props = {};

    let key = null; let ref = null; let self = null; let source = null;

    if (config != null) { … //遍历config,将除保留属性外的其他属性赋值给props self = config.self === undefined ? null : config.self; source = config.source === undefined ? null : config.source; // Remaining properties are added to a new props object for (propName in config) {

    1. if (
    2. hasOwnProperty.call(config, propName) &&
    3. !RESERVED_PROPS.hasOwnProperty(propName)
    4. ) {
    5. props[propName] = config[propName];
    6. }

    } }

    // Children can be more than one argument, and those are transferred onto // the newly allocated props object. //处理 children,会被赋值给props.children const childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = children; } else if (childrenLength > 1) { const childArray = Array(childrenLength); for (let i = 0; i < childrenLength; i++) {

    1. childArray[i] = arguments[i + 2];

    } … props.children = childArray; }

    //处理 defaultProps if (type && type.defaultProps) { const defaultProps = type.defaultProps; for (propName in defaultProps) {

    1. if (props[propName] === undefined) {
    2. props[propName] = defaultProps[propName];
    3. }

    } }

    return ReactElement( type, key, ref, self, source, ReactCurrentOwner.current, props, ); }

const ReactElement = function(type, key, ref, self, source, owner, props) { const element = { // 标记这是个 React Element $$typeof: REACT_ELEMENT_TYPE,

  1. // Built-in properties that belong on the element
  2. type: type,
  3. key: key,
  4. ref: ref,
  5. props: props,
  6. // Record the component responsible for creating this element.
  7. _owner: owner,

}; …

//最终返回element return element; };

//是否时合法的element 是object、不为null,且 object.$$typeof === REACT_ELEMENT_TYPE export function isValidElement(object) { return ( typeof object === ‘object’ && object !== null && object.$$typeof === REACT_ELEMENT_TYPE ); }

  1. <a name="RUjpx"></a>
  2. ## React Component
  3. ```javascript
  4. class AppClass extends React.Component {
  5. render() {
  6. return <p>KaSong</p>
  7. }
  8. }
  9. console.log('这是ClassComponent:', AppClass);
  10. console.log('这是Element:', <AppClass/>);
  11. function AppFunc() {
  12. return <p>KaSong</p>;
  13. }
  14. console.log('这是FunctionComponent:', AppFunc);
  15. console.log('这是Element:', <AppFunc/>);

结果显示:ClassComponent对应的Element的type字段为AppClass自身。FunctionComponent对应的Element的type字段为AppFunc自身。
image.png
注意:

  1. AppClass instanceof Function === true;
  2. AppFunc instanceof Function === true;

所以无法通过引用类型区分ClassComponent和FunctionComponent。React通过ClassComponent实例原型上的isReactComponent变量判断是否是ClassComponent。

jsx与Fiber节点

JSX是一种描述当前组件内容的数据结构,它不包含schedule、reconcile、render所需的相关信息。
以下信息不包含在JSX中:

  • 组件的更新中的优先级
  • 组件的state
  • 组件被打上的用于Renderer的标记

组件mount时,Reconciler根据jsx描述的组件内容生成组件对应的Fiber节点。
组件update时,Reconciler将JSX与Fiber节点保存的数据对比,生成组件对应的Fiber节点,并根据对比结果为Fiber节点打上标记。