天天看点

react回调函数_react源码个人笔记-版本17.0.0(笔记02修改)

react回调函数_react源码个人笔记-版本17.0.0(笔记02修改)

React 初始化的函数函数为ReactDom.render(), 进行更新有三种方式 ReactDom.render(), setState, forceUpdate 等。

// render 定义(1)

// ReactDom 执行render 的方法
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
// 目的: 调用legacyRenderSubtreeIntoContainer 函数
export function render(
 element: React$Element<any>,  // ReactElement 元素
 container: Container,  // 容器
 callback: ?Function,  // 回调函数
) {
 // 执行 legacyRenderSubtreeIntoContainer 方法
 return legacyRenderSubtreeIntoContainer(
    null,
    element,
    container,
    false,
    callback,
  );
}
           

备注: React 入口函数, 传入的参数为element, 和container 等信息, 回调函数一般不传入, 传入后会执行。

// legacyRenderSubtreeIntoContainer 函数定义(2)

// 定义   legacyRenderSubtreeIntoContainer 方法
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
// 主体逻辑: 根据container.root 有无,判断是否为初始后或更新,无: 执行生成fiberRoot, 再执行非批量
// 更新 ,有: 执行普通的更新
function legacyRenderSubtreeIntoContainer(
 parentComponent: ?React$Component<any, any>, // 初始为null 
 children: ReactNodeList,
 container: Container,
 forceHydrate: boolean,  // false 
 callback: ?Function,
) {
 
 // TODO: Without `any` type, Flow says "Property cannot be accessed on any
 // member of intersection type." Whyyyyyy.
 // 初始化, 无属性, 
 let root: RootType = (container._reactRootContainer: any);
 let fiberRoot;
 // 初始化
 if (!root) {
 // Initial mount
 // 获取_reactRootContainer 属性
    root = container._reactRootContainer = legacyCreateRootFromDOMContainer(
     container,
    forceHydrate,  // false
    );
    // 定义fiberRoot
     fiberRoot = root._internalRoot;
    if (typeof callback === 'function') {  // 回调函数
        const originalCallback = callback;  
       callback = function() {
       // 实例
       const instance = getPublicRootInstance(fiberRoot);
        originalCallback.call(instance);  // 最原始回调函数
      };
    }
     // Initial mount should not be batched.
      // 非批量更新的方式
     unbatchedUpdates(() => {  // 设置执行环境
         // 更新的节点, fiberRoot,   parentComponent 父节点   callback : 回调
        updateContainer(children, fiberRoot, parentComponent, callback);
    });
  } else {
     // 当具有root 时候, 更新的时候
       fiberRoot = root._internalRoot; //  fiberRoot
      if (typeof callback === 'function') {  // 具有回调函数
       const originalCallback = callback;
      callback = function() {  // 包裹回调函数
      // 实例
       const instance = getPublicRootInstance(fiberRoot);
       originalCallback.call(instance);  // 回调函数调用
      };
    }
       // Update  // 进行更新, 非批量更新
    updateContainer(children, fiberRoot, parentComponent, callback);  // null 回调
  }
   return getPublicRootInstance(fiberRoot);
}
           

备注: 通过container._reactRootContainer 构建基本的信息,基本的结构信息包含fiberRoot 和rootFiber, 应用更新的初始化和更新都是从fiberRoot开始。对回调函数进行包裹处理, 最后在unbatchedUpdates 执行回调函数, 初始化时,想最快速度展示页面,从而是非批量同步更新。 root 存在时, 也可以进行更新,连续调用React.ReactDom, 会走存在的路线。

// 定义legacyCreateRootFromDOMContainer 方法(3)

// 定义legacyCreateRootFromDOMContainer 方法,
// 获取root  // container._reactRootContainer
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
/// 主题逻辑: 是否需要hydrate条件生成, 调用createLegacyRoot
function legacyCreateRootFromDOMContainer(
 container: Container,  // container
 forceHydrate: boolean,  // false 
): RootType {
  // 是否需要hydrate 的判断, 可以忽略部分, 现在只考察shouldHydrate 为false 的情况
 const shouldHydrate =
 forceHydrate || shouldHydrateDueToLegacyHeuristic(container);
 // First clear any existing content.
 if (!shouldHydrate) {
   let warned = false;
    let rootSibling;
     // 清空原来container 中所有子元素
    while ((rootSibling = container.lastChild)) {
      container.removeChild(rootSibling);
    }
  }
 return createLegacyRoot(
     container,
     shouldHydrate
      ? {
     hydrate: true,
        }
      : undefined,
  );
}
           

// 定义shouldHydrateDueToLegacyHeuristic 方法(4)

// 函数shouldHydrateDueToLegacyHeuristic 定义 
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
// 主体逻辑:  获取rootElement 元素, 并 进行判断
function shouldHydrateDueToLegacyHeuristic(container) {
 const rootElement = getReactRootElementInContainer(container);
 return !!(
 rootElement &&
 rootElement.nodeType === ELEMENT_NODE &&
 rootElement.hasAttribute(ROOT_ATTRIBUTE_NAME)
  );
}
           

// 定义getReactRootElementInContainer 方法(5)

// getReactRootElementInContainer 定义
代码位置: src/react/packages/react-dom/src/client/ReactDOMLegacy.js
主题逻辑 : 先判断存在,在判断是否为document, 最后返回第一个元素
function getReactRootElementInContainer(container: any) {
 if (!container) {
 return null;
  }
 // 是否为document 
 if (container.nodeType === DOCUMENT_NODE) {
 return container.documentElement;
  } else {
 // 第一个子节点
 return container.firstChild;
  }
}
           

// 定义 createLegacyRoot 方法(6)

// 调用 createLegacyRoot 方法
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMRoot.js
// 主题逻辑: // 传入LegacyRoot 参数, 调用构造函数, 返回值为container._reactRootContainer 对应的值
export function createLegacyRoot(
 container: Container,
 options?: RootOptions,
): RootType {       
 // LegacyRoot 遗留类型的root  options : null
 //  new ReactDOMBlockingRoot() 实例 对应root  即 container.reactRootContainer                
 return new ReactDOMBlockingRoot(container, LegacyRoot, options);  // LegacyRoot
}

//备注:   src/react/packages/react-reconciler/src/ReactRootTags.js
export type RootTag = 0 | 1 | 2;
export const LegacyRoot = 0;  // 即遗留的root
export const BlockingRoot = 1;  // 阻塞的root类型
export const ConcurrentRoot = 2;    // concurrentRoot
           

// 构造函数ReactDOMBlockingRoot 定义(7)

// ReactDOMBlockingRoot 构造函数的定义
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMRoot.js
// 主题逻辑; 在原实例上,增加属性, _internalRoot 对应fiberRoot
function ReactDOMBlockingRoot(
 container: Container,
 tag: RootTag,  // rootTag的类型
 options: void | RootOptions,
) {
 
 // root / contain._reactRootContainer 的结果就是 ReactDOMBlockingRoot 实例
 // this._internalRoot 对应fiberRoot 属性
 this._internalRoot = createRootImpl(container, tag, options);  // 
 // container  容器,  tag 类型    options  参数
}
           

// 函数createRootImpl 定义(8)

// 定义 createRootImpl 函数
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMRoot.js
// 主题逻辑: 1 fiberRoot的构造, 2 fiberRoot 和container关系, 3, 基本事件的挂载
// tag : 0 , options: undefined  // root 对应fiberRoot
function createRootImpl(
 container: Container,  // 容器类型
 tag: RootTag,  // rootTag 的类型
 options: void | RootOptions,
) {
 
 // Tag is either LegacyRoot or Concurrent Root
 // 服务端渲染的参数
 const hydrate = options != null && options.hydrate === true;
 // 服务端渲染的回调参数
 const hydrationCallbacks =(options != null && options.hydrationOptions) || null;
 const mutableSources =(options != null &&options.hydrationOptions != null && options.hydrationOptions.mutableSources) ||
 null;
 // 定义root 属性
 
 // container  容器  tag: 0 hydrate : false, hydrationCallbacks : null
 // root 对应为fiberRoot 
 const root = createContainer(container, tag, hydrate, hydrationCallbacks);
 markContainerAsRoot(root.current, container);  // 
 // 设置container 与root.current 的关系
 const containerNodeType = container.nodeType;
 // enableEagerRootListeners  // true;  是否支持挂载到元素上
 // true
 if (enableEagerRootListeners) {
 // 根容器的节点, react 17 中的事件挂载
 const rootContainerElement =
 container.nodeType === COMMENT_NODE ? container.parentNode : container;
   listenToAllSupportedEvents(rootContainerElement);  // 挂载的节点
  } else {
 // 其他方式
 if (hydrate && tag !== LegacyRoot) {
 const doc =
 containerNodeType === DOCUMENT_NODE
          ? container
          : container.ownerDocument;
 // We need to cast this because Flow doesn't work
 // with the hoisted containerNodeType. If we inline
 // it, then Flow doesn't complain. We intentionally
 // hoist it to reduce code-size.
 eagerlyTrapReplayableEvents(container, ((doc: any): Document));
    } else if (
 containerNodeType !== DOCUMENT_FRAGMENT_NODE &&
 containerNodeType !== DOCUMENT_NODE
    ) {
 ensureListeningTo(container, 'onMouseEnter', null);
    }
  }
 // 服务端的参数
 if (mutableSources) {
 for (let i = 0; i < mutableSources.length; i++) {
 const mutableSource = mutableSources[i];
 registerMutableSourceForHydration(root, mutableSource);
    }
  }
 // root 的返回
 return root;  // root 对应为fiberRoot 对象
}
           

// 函数createContainer 定义(9)

// 创建FiberRoot的方法
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberReconciler.old.js
// 主体逻辑: 调用createFiberRoot 函数
//  containerInfo:  container   tag: 0, //  hydrate : false, hydrationCallbacks: null
export function createContainer(
 containerInfo: Container,
 tag: RootTag,  // rootTag 的类型
 hydrate: boolean,
 hydrationCallbacks: null | SuspenseHydrationCallbacks,
): OpaqueRoot {
 return createFiberRoot(containerInfo, tag, hydrate, hydrationCallbacks);
}
           

// 函数createFiberRoot 定义(10)

// 创建FiberRoot的节点
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberRoot.old.js
// 主题逻辑: 1 创建fiberRoot 和rootFiber, 设立两者关系, 初始化rootFiber 中updateQueue
export function createFiberRoot(
 containerInfo: any, 
 tag: RootTag,  // rootTag的类型
 hydrate: boolean,
 hydrationCallbacks: null | SuspenseHydrationCallbacks,
): FiberRoot {
   //  创建FiberRoot 节点  containerInfo 容器的信息  tag:rooTag的信息
   const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
 // 
 if (enableSuspenseCallback) {
     root.hydrationCallbacks = hydrationCallbacks;
  }

 // Cyclic construction. This cheats the type system right now because
 // stateNode is any.
 // 获取rootFiber
    const uninitializedFiber = createHostRootFiber(tag);  // 初始化rootFiber
    root.current = uninitializedFiber;  // FiberRoot 的current 执行rootFiber
    uninitializedFiber.stateNode = root;
   // rootFiber.stateNode  指向fiberRoot
    initializeUpdateQueue(uninitializedFiber); // rootFiber
    return root;
}
           

// FiberRootNode 构造函数定义(11)

// FiberRootNode 构造函数定义 // containerInfo 容器  tag: 0  hydrate: false 
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberRoot.old.js
// 主题逻辑: 根据tag 创建fiberRoot 
function FiberRootNode(containerInfo, tag, hydrate) {
 
 // fiberRoot 对象,1: 整个应用的起点, 2, 包含应用挂载的目标节点
 // 3 记录整个应用的更新过程的全部信息
 // containerInfo  容器  tag  rootTag 类型    hydrate 
 this.tag = tag;  // tag: 0  // rootTag 类型
 
 // react的各种模式
 // NoMode = 0b00000;
 // StrictMode = 0b00001;
 // BlockingMode = 0b00010;
 // ConcurrentMode = 0b00100;
 // ProfileMode = 0b01000;
 // root节点,render方法接收的第二个参数
 this.containerInfo = containerInfo;  // 容器信息
 // 只有在持久更新中会用到,也就是不支持增量更新的平台,react-dom不会用到
 this.pendingChildren = null; // 持久化更新的信息
 // 当前应用对应的Fiber对象,是Root Fiber
 this.current = null;  // root节点对应fiber 节点
 this.pingCache = null;
 
 // The earliest and latest priority levels that are suspended from committing.
 // 最老和新的在提交的时候被挂起的任务

 // 已经完成的任务的FiberRoot对象,如果你只有一个Root,那他永远只可能是这个Root对应的Fiber,或者是null
 // 在commit阶段只会处理这个值对应的任务
 this.finishedWork = null;
 // 在任务被挂起的时候,通过setTimeout设置的返回的内容
 // 用来下一次如果有新的任务挂起时, 清除没有触发的timeout

 // 在任务被挂起的时候通过setTimeout设置的返回内容,用来下一次如果有新的任务挂起时清理还没触发的timeout
 this.timeoutHandle = noTimeout;  // -1
 // 顶层的context 对象, 只有主动调用renderSubtreeIntoContainer 的时候才会用
 // 顶层context对象,只有主动调用`renderSubtreeIntoContainer`时才会有用
 this.context = null;
 this.pendingContext = null;
 this.hydrate = hydrate;
 this.callbackNode = null;
 this.callbackPriority = NoLanePriority;  // 
 this.eventTimes = createLaneMap(NoLanes); // 31位的空的数组, 中间的值位 NoLanes: 0b0000000000000000000000000000000;
 this.expirationTimes = createLaneMap(NoTimestamp);  // 过期时间  -1
 this.pendingLanes = NoLanes;  //  0b0000000000000000000000000000000;
 this.suspendedLanes = NoLanes;  //  0b0000000000000000000000000000000;
 this.pingedLanes = NoLanes; // 0b0000000000000000000000000000000;
 this.expiredLanes = NoLanes;  // 过期的  0b0000000000000000000000000000000;
 this.mutableReadLanes = NoLanes;  //  0b0000000000000000000000000000000;
 this.finishedLanes = NoLanes;  // 完成的 0b0000000000000000000000000000000;
 this.entangledLanes = NoLanes; //  0b0000000000000000000000000000000;
 this.entanglements = createLaneMap(NoLanes);  // 0b0000000000000000000000000000000;
 // 支持Hrate
 
 if (supportsHydration) {
    this.mutableSourceEagerHydrationData = null;
  }
 // 能够调度追踪, 
 if (enableSchedulerTracing) {
    this.interactionThreadID = unstable_getThreadID();
   this.memoizedInteractions = new Set();
    this.pendingInteractionMap = new Map();
  }

 if (enableSuspenseCallback) {
     this.hydrationCallbacks = null;
 }
}
           

// createLaneMap 定义(12)

// 创建一个LaneMAp 
// 代码位置: src/react/packages/react-reconciler/src/ReactFiberLane.js
// 主题逻辑: 创建一个包含31个元素的数组, 值为传入的参数
export function createLaneMap<T>(initial: T): LaneMap<T> {
 // Intentionally pushing one by one.
 // https://v8.dev/blog/elements-kinds#avoid-creating-holes
 // 空数组
 const laneMap = [];
 // 31
 for (let i = 0; i < TotalLanes; i++) {
 laneMap.push(initial);
  }
 return laneMap; // []
}
           

// createHostRootFiber 函数定义(13)

// 创建HostRootFiber 节点  tag : 0
代码位置: src/react/packages/react-reconciler/src/ReactFiber.old.js
主题逻辑: 根据传入的tag 确定mode , 调用创建rootFiber
export function createHostRootFiber(tag: RootTag): Fiber {
 // 模式定义
 
 let mode;
 // 当模式为ConcurrentMode m模式下
 if (tag === ConcurrentRoot) {
 // mode 增加严格, concurrent   
 mode = ConcurrentMode | BlockingMode | StrictMode;
 //  ConcurrentMode 模式 BlockingMode : 模式  StrictMode: 模式
  } else if (tag === BlockingRoot) {
 // Blocak   // 
 mode = BlockingMode | StrictMode;// BlockingMode 模式,  StrictMode 模式
  } else {
 // 没有模式
    mode = NoMode;
  }

 if (enableProfilerTimer && isDevToolsPresent) {
    mode |= ProfileMode;
  }
 // 创建Fiber   // 匹配模式
 return createFiber(HostRoot, null, null, mode);
 // HostRoot
}
           

// createFiber 函数定义 (14)

// 创建Fiber 节点的函数  // 创建HostRootFiber 节点
// 代码位置: src/react/packages/react-reconciler/src/ReactFiber.old.js
// 主题逻辑: 调用构造函数返回rootFiber, tag 为3, 表示root 节点
// pendingProps  : null , key: null, tag: HostRoot
const createFiber = function(
 tag: WorkTag,
 pendingProps: mixed,  // {}
 key: null | string,  // 
 mode: TypeOfMode,
): Fiber {
 
 // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
 // 创建的FiberNode节点
 return new FiberNode(tag, pendingProps, key, mode);
};
           

// FiberNode 构造函数 (15)

// FiberNode 的构造函数
// 代码位置: src/react/packages/react-reconciler/src/ReactFiber.old.js
// 主体逻辑:  定义了构造函数
function FiberNode(
 tag: WorkTag,
 pendingProps: mixed,
 key: null | string,
 mode: TypeOfMode,
) {
 // Instance
 
 // 标记不同的组件类型
 this.tag = tag;  // 类型
 // ReactElement里面的key
 this.key = key;  // key
 // ReactElement.type,也就是我们调用`createElement`的第一个参数
 this.elementType = null;
 // The resolved function/class/ associated with this fiber.
 // 异步组件resolved之后返回的内容,一般是`function`或者`class`
 this.type = null;  // 类型
 // The local state associated with this fiber.
 // 跟当前Fiber相关本地状态(比如浏览器环境就是DOM节点)
 this.stateNode = null;  // dom 节点  // dom 实例或者class 实例

 // Fiber
 // 指向他在Fiber节点树中的`parent`,用来在处理完这个节点之后向上返回
 this.return = null;  // 返回的结构
 // 单链表树结构
 // 指向自己的第一个子节点
 this.child = null;  // 子节点
 // 指向自己的兄弟结构
 // 兄弟节点的return指向同一个父节点
 this.sibling = null;  // 兄弟节点
 this.index = 0;  // 下标, 记录位置
 // ref属性
 this.ref = null;    // ref  , 最后使用de shui
// 新的变动带来的新的props
 this.pendingProps = pendingProps;  // 待更新props
 // 上一次渲染完成之后的props
 this.memoizedProps = null;  // 已经更新的props
 // 该Fiber对应的组件产生的Update会存放在这个队列里面
 this.updateQueue = null;  // 更新队列
 // 上一次渲染的时候的state
 this.memoizedState = null;  // 更新的队列
 this.dependencies = null;  // 同fiber 相关的context 事件
 // 处于什么模式 concurerntMode  或者其他模式
 // 用来描述当前Fiber和他子树的`Bitfield`
 // 共存的模式表示这个子树是否默认是异步渲染的
 // Fiber被创建的时候他会继承父Fiber
 // 其他的标识也可以在创建的时候被设置
 // 但是在创建之后不应该再被修改,特别是他的子Fiber创建之前
 this.mode = mode;  // 受父节点控制

 // Effects
 // Effect
 // 用来记录Side Effect
 this.flags = NoFlags;  // 副作用标示  PLACEMENT UPDATE , DELETE
 // 单链表用来快速查找下一个side effect
 this.nextEffect = null;
 // 子树中第一个side effect
 this.firstEffect = null;  
 // 子树中最后一个side effect
 this.lastEffect = null;
// 代表任务在未来的哪个时间点应该被完成
 // 不包括他的子树产生的任务
 this.lanes = NoLanes;   // 过期事件, 二进制位
 // 快速确定子树中是否有不在等待的变化
 this.childLanes = NoLanes;  // 子节点的
 // 在Fiber树更新的过程中,每个Fiber都会有一个跟其对应的Fiber
 // 我们称他为`current <==> workInProgress`
 // 在渲染完成之后他们会交换位置
 this.alternate = null;  // 指向旧的fiber
 // profiler 组件,计算react 的时间
 if (enableProfilerTimer) {

 this.actualDuration = Number.NaN;
 this.actualStartTime = Number.NaN;
 this.selfBaseDuration = Number.NaN;
 this.treeBaseDuration = Number.NaN;

 
 this.actualStartTime = -1;
 this.selfBaseDuration = 0;
 this.treeBaseDuration = 0;
  }
}
           

// initializeUpdateQueue 定义(16)

// 初始化更新队列 fiber: uninitlialFiber rootFiber
// 代码位置: src/react/packages/react-reconciler/src/ReactUpdateQueue.old.js
// 主题逻辑: 给rootFiber 中的updateQueue 增加一个初始的queue
export function initializeUpdateQueue<State>(fiber: Fiber): void {
 // 设置更新队列
 
 // 设置更新队列
 const queue: UpdateQueue<State> = {
 baseState: fiber.memoizedState,  // 原来的更新的基础
 // 记录数据结构, 开始
 firstBaseUpdate: null,  // 最开始BasUpdate
 // 记录数据结构, 结束
 lastBaseUpdate: null,
 shared: {
 pending: null,
    },
 effects: null,  //   当前update 的副作用
  };
 //    更新队列
 // rootFiber 中的updateQueue ,设置一个初始值
 fiber.updateQueue = queue;  // rootFiber 的updateQueue 设置更新
 // 给uninitlialFiber 
 // 设置rootFiber的更新队列
}
           

// markContainerAsRoot 定义(17)

// hostRoot  fiberRoot.current   node: container
/// 定义markContainerAsRoot 
// 代码位置: src/react/packages/react-dom/src/client/ReactDOMComponentTree.js
// 主题逻辑: 设置container.internalContainerInstanceKey 指向rootFiber
export function markContainerAsRoot(hostRoot: Fiber, node: Container): void {
 // container. internalContainerInstanceKey  = fiberRoot.current
 // 设置指向
 node[internalContainerInstanceKey] = hostRoot;
}
// 备注信息: 
const randomKey = Math.random()
  .toString(36)
  .slice(2);
const internalContainerInstanceKey = '__reactContainer$' + randomKey;
           

// listenToAllSupportedEvents 定义(18)

// 当enableEagerRootListeners  对container 的元素的绑定
// rootContainerElement: container 
// 代码位置: src/react/packages/react-dom/src/events/DOMPluginEventSystem.js
// 主题逻辑: 将触发的事件绑定的container , 冒泡阶段和触发分别绑定
export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {
 // ture
 if (enableEagerRootListeners) {
 // 初始为undefined
 if ((rootContainerElement: any)[listeningMarker]) {
      return;
    }
 // 初始false
    (rootContainerElement: any)[listeningMarker] = true;
 // 各种事件类型
 allNativeEvents.forEach(domEventName => {
 // 不进行冒泡代理的事件和  必须要绑定在指定元素的事件
 if (!nonDelegatedEvents.has(domEventName)) {
 //  冒泡阶段的事件代理
   listenToNativeEvent(
     domEventName,  // 事件类型
    false,
    ((rootContainerElement: any): Element),
     null,
      );
      }
    // 在触发阶段的绑定
    listenToNativeEvent(
      domEventName,
     true,
     ((rootContainerElement: any): Element),
      null,
      );
    });
  }
}

// 备注
export const deferRenderPhaseUpdateToNextBatch = true;
           

流程图

react回调函数_react源码个人笔记-版本17.0.0(笔记02修改)

总结信息:

1 通过ReactDom.render() 进行初始化流程, 再次更新的时候也可以通过ReactDom.render() 进行更新。

2 container.reactRootContainer 为一个ReactDOMBlockingRoot实例。实例的_internalRoot 为fiberRoot ,

3 创建rootFiber 对象, 设置rootFiber 与container 的关系,在游览器下设置部分事件挂载在container.

4 初始化queue 添加到rootFiber 的updateQueue上。