react 源碼

react 源碼

  • React.js 文件
const React = {
  Children: {
    map,
    forEach,
    count,
    toArray,
    only
  },

  createRef,
  Component,
  PureComponent,

  createContext,
  forwardRef,
  lazy,
  memo,

  useCallback,
  useContext,
  useEffect,
  useImperativeHandle,
  useDebugValue,
  useLayoutEffect,
  useMemo,
  useReducer,
  useRef,
  useState,

  Fragment: REACT_FRAGMENT_TYPE,
  Profiler: REACT_PROFILER_TYPE,
  StrictMode: REACT_STRICT_MODE_TYPE,
  Suspense: REACT_SUSPENSE_TYPE,
  unstable_SuspenseList: REACT_SUSPENSE_LIST_TYPE,

  createElement: __DEV__ ? createElementWithValidation : createElement,
  cloneElement: __DEV__ ? cloneElementWithValidation : cloneElement,
  createFactory: __DEV__ ? createFactoryWithValidation : createFactory,
  isValidElement: isValidElement,

  version: ReactVersion,

  unstable_withSuspenseConfig: withSuspenseConfig,

  __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals
};

if (enableFlareAPI) {
  React.unstable_useResponder = useResponder;
  React.unstable_createResponder = createResponder;
}

if (enableFundamentalAPI) {
  React.unstable_createFundamental = createFundamental;
}

if (enableScopeAPI) {
  React.unstable_createScope = createScope;
}

//注意:有些API添加了特性標誌。
//確保開源的穩定構建
//不要修改react對象以避免deopts。
//同樣,我們不要在穩定的構建中公開它們的名稱。

if (enableJSXTransformAPI) {
  if (__DEV__) {
    React.jsxDEV = jsxWithValidation;
    React.jsx = jsxWithValidationDynamic;
    React.jsxs = jsxWithValidationStatic;
  } else {
    React.jsx = jsx;
    // 我們可能希望在內部對jsxs進行特殊處理,以利用靜態子級的優勢。
    // 現在我們可以發佈相同的prod函數
    React.jsxs = jsx;
  }
}
  • ReactBaseClasses.js
/**
 * 用於組件更新狀態的基類幫助程序。
 */
function Component(props, context, updater) {
  this.props = props;
  this.context = context;
  // 如果組件具有字符串 refs,我們稍後將分配不同的對象
  this.refs = emptyObject;
  // 我們初始化默認的更新程序,但真實的更新程序會由渲染器注入
  this.updater = updater || ReactNoopUpdateQueue;
}

Component.prototype.isReactComponent = {};

// 1. setState 方法
Component.prototype.setState = function(partialState, callback) {
  // ...
  this.updater.enqueueSetState(this, partialState, callback, "setState");
};

// 2. forceUpdate 方法
Component.prototype.forceUpdate = function(callback) {
  this.updater.enqueueForceUpdate(this, callback, "forceUpdate");
};

// 3. 不推薦使用的 API 的棄用警告
// defineDeprecationWarning(fnName, deprecatedAPIs[fnName]);

/**
 * 具有默認淺層相等檢查的便利組件
 */
function PureComponent(props, context, updater) {
  this.props = props;
  this.context = context;
  this.refs = emptyObject;
  this.updater = updater || ReactNoopUpdateQueue;
}

const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// 避免這些方法的額外原型跳轉.
Object.assign(pureComponentPrototype, Component.prototype);
pureComponentPrototype.isPureReactComponent = true;

export { Component, PureComponent };
  • ReactNoopUpdateQueue.js
const didWarnStateUpdateForUnmountedComponent = {};
// 警告Noop
function warnNoop(publicInstance, callerName) {
  if (__DEV__) {
    // ...
    // 堆棧溢出報錯
    warningWithoutStack(
      false,
      "Can't call %s on a component that is not yet mounted. " +
        "This is a no-op, but it might indicate a bug in your application. " +
        "Instead, assign to `this.state` directly or define a `state = {};` " +
        "class property with the desired state in the %s component.",
      callerName,
      componentName
    );
  }
}
// 這是更新隊列抽象的 API
const ReactNoopUpdateQueue = {
  /**
   * 檢查是否已經安裝了此複合組件
   * @param {ReactClass} publicInstance 我們要測試的實例.
   * @return {boolean} True if mounted, false otherwise.
   */
  isMounted: function(publicInstance) {
    return false;
  },
  /**
   * 強制更新. 只有在確定在DOM事務中‘not’時才應該調用它
   * @param {ReactClass} publicInstance 應該重新渲染的實例
   * @param {?function} callback 組件更新之後調用.
   * @param {?string} callerName 公共API中調用函數的名稱
   */
  enqueueForceUpdate: function(publicInstance, callback, callerName) {
    warnNoop(publicInstance, "forceUpdate");
  },
  /**
   * 取代所有的狀態,始終使用 this.setState 來改變狀態
   * 你應該將 this.state 視爲不可變
   * 無法保證 this.state 會立即更新,因此在調用此方法後訪問 this.state 可能會返回舊值。
   * @param {ReactClass} publicInstance (同上)
   * @param {object} completeState 下一個狀態.
   * @param {?function} callback (同上)
   * @param {?string} callerName (同上)
   */
  enqueueReplaceState: function(
    publicInstance,
    completeState,
    callback,
    callerName
  ) {
    warnNoop(publicInstance, "replaceState");
  },
  /**
   * 設置狀態的子集
   * @param {ReactClass} publicInstance (同上)
   * @param {object} partialState 下一個要與狀態合併的部分狀態
   * @param {?function} callback (同上)
   * @param {?string} Name (同上)
   */
  enqueueSetState: function(
    publicInstance,
    partialState,
    callback,
    callerName
  ) {
    warnNoop(publicInstance, "setState");
  }
};
export default ReactNoopUpdateQueue;
  • ReactElement.js
/**
 * 工廠函數創建一個 react 元素
 */
const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // 這個標籤允許我們將其唯一地標識爲一個react元素
    $$typeof: REACT_ELEMENT_TYPE,

    // 屬於元素的內置屬性
    type: type,
    key: key,
    ref: ref,
    props: props,

    // 記錄負責創建此元素的組件
    _owner: owner
  };

  if (__DEV__) {
    // 這個驗證標誌是可變的。
    // 我們把它放在外部的後存儲設備上爲了我們可以凍結整個object。
    // 一旦在常用的開發環境中實現這一點,就可以使用WeakMap替換他們
    element._store = {};

    // 爲了使ReactElements更容易用於測試,我們設置這個驗證標誌不可枚舉
    // (在可能的情況下,他應該包含我們運行測試的每個環境)
    Object.defineProperty(element._store, "validated", {
      configurable: false,
      enumerable: false,
      writable: true,
      value: false
    });
    // self and source are DEV only properties.
    Object.defineProperty(element, "_self", {
      configurable: false,
      enumerable: false,
      writable: false,
      value: self
    });
    // 兩個元素創建在兩個不同的地方爲了測試目的應該被考慮爲是相等的,因此我們從枚舉中隱藏他們
    Object.defineProperty(element, "_source", {
      configurable: false,
      enumerable: false,
      writable: false,
      value: source
    });
    if (Object.freeze) {
      Object.freeze(element.props);
      Object.freeze(element);
    }
  }

  return element;
};

export function jsx(type, config, maybeKey) {
  let propName;

  // 提取保留名稱
  const props = {};

  let key = null;
  let ref = null;

  // key 會被傳遞進 props中.
  // 如果key是顯示聲明的,這會導致潛在的問題 (例如. <div {...props} key="Hi" />,我們想要阻止 key 的傳遞,但是作爲一箇中間步驟,除了 <div {...props} key="Hi" /> 之外,我們將對所有內容使用 jsxDEV,因爲我們也沒有辦法確認 key 是否顯式聲明爲未定義。
  if (maybeKey !== undefined) {
    key = "" + maybeKey;
  }

  if (hasValidKey(config)) {
    key = "" + config.key;
  }

  if (hasValidRef(config)) {
    ref = config.ref;
  }

  // 剩餘的屬性被添加進新的 props 對象中
  for (propName in config) {
    if (
      hasOwnProperty.call(config, propName) &&
      !RESERVED_PROPS.hasOwnProperty(propName)
    ) {
      props[propName] = config[propName];
    }
  }

  // 解析默認的 props
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }

  return ReactElement(
    type,
    key,
    ref,
    undefined,
    undefined,
    ReactCurrentOwner.current,
    props
  );
}
/**
 * 創建並返回一個給定類型的 React 元素
 */
export function createElement(type, config, children) {
  let propName;

  // 提取保留名稱
  const props = {};

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

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

    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) {
      if (
        hasOwnProperty.call(config, propName) &&
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }

  // Children 可以是一個以上的參數,他們被轉移到新分配的 props 對象上。
  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++) {
      childArray[i] = arguments[i + 2];
    }
    if (__DEV__) {
      if (Object.freeze) {
        Object.freeze(childArray);
      }
    }
    props.children = childArray;
  }

  // Resolve default props
  if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  if (__DEV__) {
    if (key || ref) {
      const displayName =
        typeof type === "function"
          ? type.displayName || type.name || "Unknown"
          : type;
      if (key) {
        defineKeyPropWarningGetter(props, displayName);
      }
      if (ref) {
        defineRefPropWarningGetter(props, displayName);
      }
    }
  }
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props
  );
}
  • ReactHooks.js

https://github.com/facebook/react

dispatcher.useContext

dispatcher.useState

dispatcher.useRef

dispatcher..useEffect

dispatcher.useCallback

dispatcher.useResponder

react-dom 源碼

  • index.js
export type DOMContainer =
  | (Element & {
      _reactRootContainer: ?_ReactRoot,
      _reactHasBeenPassedToCreateRootDEV: ?boolean,
    })
  | (Document & {
      _reactRootContainer: ?_ReactRoot,
      _reactHasBeenPassedToCreateRootDEV: ?boolean,
    });
// 判斷提供的DOM節點是否是有效的節點元素
function isValidContainer(node) {
  return !!(
    node &&
    (node.nodeType === ELEMENT_NODE ||
      node.nodeType === DOCUMENT_NODE ||
      node.nodeType === DOCUMENT_FRAGMENT_NODE ||
      (node.nodeType === COMMENT_NODE &&
        node.nodeValue === ' react-mount-point-unstable '))
  );
}
const ReactDOM: Object = {
    ...,
    render(
        element: React$Element<any>,
        container: DOMContainer,
        callback: ?Function ) {
            // 有效性驗證
            invariant(
                isValidContainer(container),
                'target container is not a DOM element'
            );
            // 堆棧警告
            warningWithoutStack();
            return legacyRenderSubtreeIntoContainer(
                null,
                element,
                container,
                true,
                callback
            )
        }
}
發佈了139 篇原創文章 · 獲贊 92 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章