2019-07-08 22:10:50 qq_32281471 阅读数 826
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    57551 人正在学习 去看看 李宁

源码分析是大多数开发者忽略的问题,然而想要在技术上有更深的造诣,源码分析必不可少!

React 项目托管在 GitHub
项目开发指引也可见官网 How to Contribute
文章使用的版本为v16.8.6

开始

克隆代码到本地

git clone https://github.com/facebook/react.git

在这里插入图片描述
查看分支,git branch -a
在这里插入图片描述
切换到 16.8.6 分支,git checkout 16.8.6
在这里插入图片描述
安装依赖,yarn install

由源码编译

项目目录结构如图。
在这里插入图片描述
官网对编译的提示
在这里插入图片描述
从源码编译出 react.development.jsreact-dom.development.js
执行

yarn run build react/index, react-dom/index

在这里插入图片描述
构建出的文件,保存在 build/node_modules/react,有 commonjs 和 umd 两个版本。
在这里插入图片描述
直接打开 fixtures/packaging/babel-standalone/dev.html
在这里插入图片描述
页面使用的是最新编译出来的 react.development.js 和 react-dom.development.js
在这里插入图片描述

更改代码测试效果

在 setState 内部添加一个 log,更改 packages/react/src/ReactBaseClasses.js
在这里插入图片描述
重新编译 react ,yarn run build react/index
在这里插入图片描述
查看 react.development.js,在 build/node_modules/react/umd/react.development.js
在这里插入图片描述
至此,代码编译都已经成功了。

使用自己编译出来的 react、react-dom

使用 create-react-app 初始化一个项目,删除 package.json 中 dependencies 中的 react、react-dom。
在这里插入图片描述
进入之前编译好的 react、react-dom 目录,分别执行 yarn link
再到项目目录,输入yarn link react react-dom,启动 yarn start 即可。

2019-12-20 16:36:42 wlqdbtx 阅读数 28
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    57551 人正在学习 去看看 李宁

在开始看react源码前觉得代码量应该会非常庞大,然而在看完react源码后发现实际上react的源码只是一些API和数据结构的定义,真正的更新渲染逻辑是react-dom这块源码里控制的。

本此源码解析系列不包括dev环境下的代码,只对主流程代码进行讲解。

react的源码地址为:react

我们先来看下react的目录结构:

下面让我们看下react对我们暴露的API:/packages/react/src/React.js

const React = {
  Children: {
    map,
    forEach,
    count,
    toArray,
    only,
  },

  createRef,
  Component,
  PureComponent,

  createContext,
  forwardRef,
  lazy,
  memo,

  Fragment: REACT_FRAGMENT_TYPE,
  StrictMode: REACT_STRICT_MODE_TYPE,
  Suspense: REACT_SUSPENSE_TYPE,

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

  version: ReactVersion,

  unstable_ConcurrentMode: REACT_CONCURRENT_MODE_TYPE,
  unstable_Profiler: REACT_PROFILER_TYPE,

  __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: ReactSharedInternals,
};

createElement

React.createElement这个方法用于创建一个ReactElement,也就是jsx语法解析后的对象,如

// jsx
<div id="app">msg</div>

// 上述jsx解析完成后的结构
React.createElement('div', { id: 'app' }, 'msg')

下面让我们看下createElement这个函数:

const RESERVED_PROPS = {
  key: true,
  ref: true,
  __self: true,
  __source: true,
};

function hasValidRef(config) {
  return config.ref !== undefined;
}
function hasValidKey(config) {
  return config.key !== undefined;
}

// React.createElement('div', { id: 'btn' }, '提交');
// config包含组件上的所有props,包括:事件、key、ref、各种属性
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) {
    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
    // 这里遍历传入的config
    for (propName in config) {
      if (
        hasOwnProperty.call(config, propName) &&
        // 不是key和ref
        !RESERVED_PROPS.hasOwnProperty(propName)
      ) {
        props[propName] = config[propName];
      }
    }
  }

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  // 这里对children特殊处理,如果传入多个则props.children为数组,否则直接等于传入的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++) {
      childArray[i] = arguments[i + 2];
    }
    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];
      }
    }
  }
  // props不包含key和ref
  return ReactElement(
    type,
    key,
    ref,
    self,
    source,
    ReactCurrentOwner.current,
    props,
  );
}

让我们再看几个例子来理解下

从上面几个例子可以看出type的几种取值(这里一定要理解type指向的值,后续更新流程中会有很多地方用到type)

  • 当为原生标签时type为标签对应的字符串,如 'div'。
  • 当为function或者class等自定义组件时,type表示组件的function或者class。

现在让我们看下返回的element的结构

const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // This tag allows us to uniquely identify this as a React Element
    $$typeof: REACT_ELEMENT_TYPE,

    // Built-in properties that belong on the element
    type: type,
    key: key,
    ref: ref,
    props: props,

    // Record the component responsible for creating this element.
    _owner: owner,
  };

  return element;
};

上面还剩两个属性没讲到

1、:REACT_ELEMENT_TYPE,表示这是通过createElement创建的。在react中还有一种情况是通过ReactDOM.createPoratl()创建,这时它的'$$typeof'为REACT_PORTAL_TYPE。

2、'_owner':表示创建当前组件的class组件的实例,用于后续ref时使用。因为字符串类型的ref是要绑定到class实例的this.refs.xxx上的。

注意:这里留意一下$$typeof和type这两个属性,后续更新逻辑中会有大量对这两个属性的判断,比较容易混淆。

createFactory

这个方法就是将createElement的type绑定一个固定的类型,后续不需要传type了。

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

cloneElement

用于复制一个element

export function cloneElement(element, config, children) {
  // 校验下element不能为空,若为空则throw new Error
  invariant(
    !(element === null || element === undefined),
    'React.cloneElement(...): The argument must be a React element, but you passed %s.',
    element,
  );

  let propName;

  // Original props are copied
  const props = Object.assign({}, element.props);

  // Reserved names are extracted
  let key = element.key;
  let ref = element.ref;
  // Self is preserved since the owner is preserved.
  const self = element._self;
  // Source is preserved since cloneElement is unlikely to be targeted by a
  // transpiler, and the original source is probably a better indicator of the
  // true owner.
  const source = element._source;

  // Owner will be preserved, unless ref is overridden
  let owner = element._owner;

  // 复制config到element.props里,并更新key和ref
  if (config != null) {
    if (hasValidRef(config)) {
      // Silently steal the ref from the parent.
      ref = config.ref;
      owner = ReactCurrentOwner.current;
    }
    if (hasValidKey(config)) {
      key = '' + config.key;
    }

    // Remaining properties override existing props
    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];
        }
      }
    }
  }

  // Children can be more than one argument, and those are transferred onto
  // the newly allocated props object.
  const childrenLength = arguments.length - 2;
  // 如果传入child,则更新props.children
  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];
    }
    props.children = childArray;
  }

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

isValidElement

根据$$typeof来判断是否是正确的element格式

export function isValidElement(object) {
  return (
    typeof object === 'object' &&
    object !== null &&
    object.$$typeof === REACT_ELEMENT_TYPE
  );
}

 

2017-02-18 18:42:01 u013510838 阅读数 5480
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    57551 人正在学习 去看看 李宁

1 源码结构

我们分析的React源码version为16.0.0-alpha.3,源码目录如下图所示。

Markdown

含义如下

  • addons:插件,一些比较有用的工具,如transition动画
  • isomorphic: 同构,服务端在页面初次加载时,将所有方法渲染好,一次性交给客户端。这样可以减少Ajax
  • shared: 共用方法,一些utils
  • test: 测试方法
  • renderers: React代码核心,大部分功能实现代码都在其中
    • dom:
    • stack/client: 各种ReactComponent
    • stack/server: 服务端渲染方法
    • shared: CSSProperty, DOMProperty, 合成事件处理,DOM操作方法,如findDOMNode, setInnerHTML等。
    • fiber: 重写了React核心算法,架构进行了升级,未来可能会应用。
    • native: ReactNative, 跨平台实现Android和iOS
    • shared:
    • stack/reconciler: 协调器,包含自定义组件实现ReactCompositeComponent.js, setState机制,生命周期方法流程,DOM diff等
    • shared/event: 事件处理
    • fiber:实验代码,未来可能会应用

2 重要模块

React代码还是相当复杂的,我们需要深入理解重要模块的源码机制。后面会有几篇文章针对每个模块进行分析

  • 元素和组件的创建:ReactElement元素是一个数据类,包含props refs key等变量。ReactComponent是一个控制类,包含组件状态,操作方法等,是React对内的一个很重要的类。它有不同的子类实现,如DOM原生组件ReactDOMComponent,React自定义组件ReactCompositeComponent,文本组件ReactDOMTextComponent。

    React利用createClass()创建组件类对象,createElement()创建组件实例对象。JSX经过babel转译后,实际是调用createElement()创建实例对象。这部分代码分析参见 React源码分析2 — 组件和对象的创建(createClass,createElement)

  • React组件插入DOM流程:创建了ReactElement和ReactComponent后,还需要将virtual DOM插入真实DOM中,这样浏览器才能渲染。React会利用virtual DOM生成HTML,然后将HTML插入父组件中。而root组件正好是我们在ReactDOM.render()方法中传入的DOM原生对象。这部分代码分析参见 React源码分析3 — React组件插入DOM流程

  • React生命周期:React吸引人的一个地方在于,有比较清晰的生命周期调用方法。利用模板模式使得代码结构清晰而又不失灵活性。前端一直以来有个让人诟病的地方在于,大家代码风格各异,没有像Android那样比较清晰的流程方法,使得维护起来比较麻烦。React的出现大大解决了这个难题。这部分代码分析参见 React源码分析4 — React生命周期详解

  • setState实现机制:作为一种前端流行框架,虽然React专注于MVVM中的View,但它也实现了一套View和数据绑定的方法。这个正是setState。同时,利用队列和transaction来管理setState,避免了一些重复无谓的界面更新。这部分代码分析参见 React源码分析5 — setState机制

总之,作为当下前端最流行的框架,React源码还是值得我们细细分析的。从源码中我们也能学到很多优秀的设计模式,让我们的代码更加清晰好维护。文章中如有不正确的地方,欢迎指正!

2019-12-11 15:54:54 andriod132 阅读数 12
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    57551 人正在学习 去看看 李宁

近期在学习react,把源码clone下来学习下,用vscode在单元测试中打断点调试,不懂怎么配置,所以请教下大家。

下图是源码目录及launch.json配置文件,目前只配置了这个。

2019-12-27 16:07:35 m_review 阅读数 58
  • 完全征服React Native

    React Native是Facebook于2015年推出的跨平台开发工具,可用于开发Android和iOS App,并且同时具有混合开发的优点(热更新,跨平台)以及本地App的性能。 本课程采用新的ES6开发,主要内容包括ReactNative的基础知识,ReactNative的布局,组件,API,封装本地API和组件,发布ReactNative App,本地与ReactNative深度结合

    57551 人正在学习 去看看 李宁

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
            )
        }
}

react源码分析

阅读数 221

react 源码学习

阅读数 41

没有更多推荐了,返回首页