react 源码学习

源码学习记录

  • 1. React Api
  • 2. React中的创建更新
  • 3. React调度过程(Fiber Scheduler)
  • 4. 组件如何进行更新
  • 5. 组件更新完成后进行的操作
    • 1. 虚拟Dom对比
    • 2. 渲染中出现错误的处理过程
  • 6. 真实Dom更新
  • 7. 各种功能的实现(content,ref,hydrate...)
  • 8. Suspense (超前体验)
  • 9. Hooks

1. React Api

  • Fiber: react 16 中引入,解决js单线程运行时,计算量太大导致的动画卡帧和交互卡顿的问题。
  • Flow Type: react中用到的类型检测。
  • jsx到javaScript的转变: createElement(type, config, children) (react.js文件) 接受三个参数,使用babel转变查看:babel
    react 源码学习_第1张图片
    createElement需要注意几点:
  1. 标签转换是通过React的createElement方法实现,该方法接受三个参数:分别为dom类型,props属性,第三个参数及之后的都算作该标签的子节点。
  2. 原生标签显示为字符串,而自定义组件以大写字母开头,显示为变量。
  3. 其中createElement()方法中获取默认属性的方式: 如果定义了defaultProps,则会设置默认的props值。
 if (type && type.defaultProps) {
    const defaultProps = type.defaultProps;
    for (propName in defaultProps) {
      if (props[propName] === undefined) {
        props[propName] = defaultProps[propName];
      }
    }
  }
  1. 该方法返回ReactElement
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;
}

其中需要注意 $$typeof 表示react的节点,通过createElement() 方法创建的都是react的节点。

  • Component和PureComponent:ReactBaseClasses.js 文件)
    PureComponent 继承自 Component,继承方法使用了很典型的寄生组合式。PureComponent通过prop和state的浅比较来实现shouldComponentUpdate,所以当PureComponent的组件中对象或数组的值改变单引用地址不变则不会更新数据。
Component.prototype.setState = function(partialState, callback) {
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
};

eg: 当state中数组arr的值为['1'] 可以通过下面的拓展运算符在PureComponent中得到更新

  this.setState({
	  arr: [...arr, '2']
  })
	function ComponentDummy() {}
	ComponentDummy.prototype = Component.prototype;
	const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
	pureComponentPrototype.constructor = PureComponent;
	// Avoid an extra prototype jump for these methods.
	Object.assign(pureComponentPrototype, Component.prototype);
	// 检查组件是否需要更新的一个判断
	pureComponentPrototype.isPureReactComponent = true;
  • render
    1. 在reactDOM.js 中render 返回 legacyRenderSubtreeIntoContainer() 函数
  render(
    element: React$Element<any>,
    container: DOMContainer,
    callback: ?Function,
  ) {
    invariant(
      isValidContainer(container),
      'Target container is not a DOM element.',
    );
    return legacyRenderSubtreeIntoContainer(
      null,
      element,
      container,
      false,  //  这个参数为 true 时表明了是服务端渲染, false 为客户端渲染
      callback,
    );
  },
  1. legacyRenderSubtreeIntoContainer 中 一部分是没有 root 之前我们首先需要创建一个 root,第二部分是有 root 之后的渲染流程。
    1⃣️ : 创建root节点
function legacyCreateRootFromDOMContainer(
  container: DOMContainer,
  forceHydrate: boolean,
): _ReactSyncRoot {
  const shouldHydrate =
    forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
  // First clear any existing content.
  if (!shouldHydrate) {
    let warned = false;
    let rootSibling;
    while ((rootSibling = container.lastChild)) {
      container.removeChild(rootSibling);  // ** 容器内部不要含有任何的子节点。一是肯定会被移除掉,二来还要进行 DOM 操作,可能还会涉及到重绘回流等等。
    }
  }
  // Legacy roots are not batched.
  return new ReactSyncRoot(container, LegacyRoot, shouldHydrate);  // 创建了一个 FiberRoot 对像
}

创建了一个 FiberRoot 对象,并挂载到了 _internalRoot 上

function ReactSyncRoot(
  container: DOMContainer,
  tag: RootTag,
  hydrate: boolean,
) {
  // Tag is either LegacyRoot or Concurrent Root
  const root = createContainer(container, tag, hydrate);
  this._internalRoot = root;
}

function createContainer(
  containerInfo: Container,
  tag: RootTag,
  hydrate: boolean,
): OpaqueRoot {
  return createFiberRoot(containerInfo, tag, hydrate);
}

**content: ** 多用于多层父子组件关系传递信息。
ConcurrentMode : ConcurrentMode会降低包裹的子组件渲染的优先级。

2. React中的创建更新

React中对比一个ClassComponent是否需要更新: 只有两个地方。一是看有没有shouldComponentUpdate方法,二就是PureComponent判断
react中比较多的数据结构使用二进制: 为了简化类型比较,以及类型复合的方向

3. React调度过程(Fiber Scheduler)

什么是Fiber?
每一个ReactElement对应一个Fiber对象,记录节点的各种状态,串联整个应用形成树结构。
什么是update?
用于记录组件状态的改变。

4. 组件如何进行更新

5. 组件更新完成后进行的操作

1. 虚拟Dom对比

2. 渲染中出现错误的处理过程

6. 真实Dom更新

7. 各种功能的实现(content,ref,hydrate…)

8. Suspense (超前体验)

9. Hooks

你可能感兴趣的:(进阶学习)