React16源码: React中的updateClassComponent的源码实现

React 组件类型详解:类组件 vs. 函数组件 React 是一个用于构建用户界面的 JavaScript 库,其核心思想是组件化开发。React 组件可以分为类组件(Class Components)和函数组件(Function Components),它们在设计理念、使用方式和适用场景上有所不同。随着 React Hooks 的引入,函数组件的能力得到了极大增强,逐渐成为开发者的首选。 阅读详情

ClassComponent 的更新


1 ) 概述

  • 在 react 中 class component,是一个非常重要的角色
  • 它承担了 react 中 更新整个应用的API
    • setState
    • forceUpdate
  • 在react当中,只有更新了state之后,整个应用才会重新进行渲染
  • 在 class component 中, 它的逻辑相对复杂

2 )源码

在 packages/react-reconciler/src/ReactFiberBeginWork.js

// 这个方法就是更新 ClassComponent 组件的一个过程
function updateClassComponent(
  current: Fiber | null,
  workInProgress: Fiber,
  Component: any,
  nextProps,
  renderExpirationTime: ExpirationTime,
) {
  // Push context providers early to prevent context stack mismatches.
  // During mounting we don't know the child context yet as the instance doesn't exist.
  // We will invalidate the child context in finishClassComponent() right after rendering.
  // 先跳过 context 相关的逻辑
  let hasContext;
  if (isLegacyContextProvider(Component)) {
    hasContext = true;
    pushLegacyContextProvider(workInProgress);
  } else {
    hasContext = false;
  }
  prepareToReadContext(workInProgress, renderExpirationTime);

  // instance 就是我们 class component,通过new这个class获取的一个对象
  const instance = workInProgress.stateNode;
  // 在这里面,它声明了一个 shouldUpdate 的一个属性
  let shouldUpdate; 
  // 先判断instance是否存在, 比如说我们第一次通过 ReactDOM.render 进行渲染的过程当中
  // 在从上往下第一次渲染的过程当中,第一次更新到 class component 的时候
  // 它的instance肯定是不存在的,因为它还没有被更新过,所以它的节点肯定是没有被创建的
  if (instance === null) {
    // 接下去, 判断一下current是否等于null
    // current等于null的情况是代表在进入第一次渲染,因为current它还不存在
    // 如果current不等于null, 代表我们至少已经经历过一次渲染了
    // 这时候 instance 不存在,而 current 存在,说明第一次渲染的时候没有创建这个instance
    // 同样说明这个组件是被 suspended 的,一个组件处于suspended的状态
    // 在这里react认为它相当于是第一次被渲染, 在初次渲染的时候,只是抛出了一个promise
    // 并没有真正的渲染出它的子节点, 抛出了一个promise之后,接下去的渲染就结束了
    if (current !== null) {
      // An class component without an instance only mounts if it suspended
      // inside a non- concurrent tree, in an inconsistent state. We want to
      // tree it like a new mount, even though an empty version of it already
      // committed. Disconnect the alternate pointers.
      current.alternate = null;
      workInProgress.alternate = null;
      // Since this is conceptually a new fiber, schedule a Placement effect
      workInProgress.effectTag |= Placement;
    }
    // In the initial pass we might need to construct the instance.
    // 对于没有instance的一个情况,需要去创建 class instance
    constructClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
    // 并且要mount这个 class instance
    mountClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
    // 在第一次渲染的时候,会执行上述两个方法,并且 shouldUpdate = true;
    shouldUpdate = true;
  } else if (current === null) {
    // In a resume, we'll already have an instance we can reuse.
    // 在 有instance 和 没有 current 的情况下,这种是之前被中断的
    // 在执行 class component 的 render 方法的时候 报错,但 instance 已被创建
    // 代表着可以复用 instance
    shouldUpdate = resumeMountClassInstance(
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
  } else {
    // 对于又有 current 又有 instance的情况,说明组件已经被重新渲染了
    // 这个 updateClassInstance 方法和 上述 resumeMountClassInstance 类似
    // 最大的区别是 内部判断 comonentDidUpdate 
    shouldUpdate = updateClassInstance(
      current,
      workInProgress,
      Component,
      nextProps,
      renderExpirationTime,
    );
  }
  // 这里最终调用 finishClassComponent
  return finishClassComponent(
    current,
    workInProgress,
    Component,
    shouldUpdate,
    hasContext,
    renderExpirationTime,
  );
}
  • 进入 constructClassInstance

    function constructClassInstance(
      workInProgress: Fiber,
      ctor: any,
      props: any,
      renderExpirationTime: ExpirationTime,
    ): any {
      // 先跳过 context 相关
      let isLegacyContextConsumer = false;
      let unmaskedContext = emptyContextObject;
      let context = null;
      const contextType = ctor.contextType;
      // 
      if (typeof contextType === 'object' && contextType !== null) {
        // 跳过 DEV
        if (__DEV__) {
          if (
            contextType.$$typeof !== REACT_CONTEXT_TYPE &&
            !didWarnAboutInvalidateContextType.has(ctor)
          ) {
            didWarnAboutInvalidateContextType.add(ctor);
            warningWithoutStack(
              false,
              '%s defines an invalid contextType. ' +
                'contextType should point to the Context object returned by React.createContext(). ' +
                'Did you accidentally pass the Context.Provider instead?',
              getComponentName(ctor) || 'Component',
            );
          }
        }
    
        context = readContext((contextType: any));
      } else {
        unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
        const contextTypes = ctor.contextTypes;
        isLegacyContextConsumer =
          contextTypes !== null && contextTypes !== undefined;
        context = isLegacyContextConsumer
          ? getMaskedContext(workInProgress, unmaskedContext)
          : emptyContextObject;
      }
    
      // Instantiate twice to help detect side-effects.
      if (__DEV__) {
        if (
          debugRenderPhaseSideEffects ||
          (debugRenderPhaseSideEffectsForStrictMode &&
            workInProgress.mode & StrictMode)
        ) {
          new ctor(props, context); // eslint-disable-line no-new
        }
      }
    
      // ctor 是 construct 的一个缩写 这个 ctor 就是在 ReactElement当中
      // 存在的那个type,也就是 class component 定义的那个class
      // 传入 props和context,对应于 ReactBaseClasses.js 里面,Component 函数 接收的这两个参数
      // 第三个参数 updater 后面在 adoptClassInstance 里面设置
      const instance = new ctor(props, context);
      // 获取 state
      const state = (workInProgress.memoizedState =
        instance.state !== null && instance.state !== undefined
          ? instance.state
          : null);
      adoptClassInstance(workInProgress, instance);
    
      if (__DEV__) {
        if (typeof ctor.getDerivedStateFromProps === 'function' && state === null) {
          const componentName = getComponentName(ctor) || 'Component';
          if (!didWarnAboutUninitializedState.has(componentName)) {
            didWarnAboutUninitializedState.add(componentName);
            warningWithoutStack(
              false,
              '`%s` uses `getDerivedStateFromProps` but its initial state is ' +
                '%s. This is not recommended. Instead, define the initial state by ' +
                'assigning an object to `this.state` in the constructor of `%s`. ' +
                'This ensures that `getDerivedStateFromProps` arguments have a consistent shape.',
              componentName,
              instance.state === null ? 'null' : 'undefined',
              componentName,
            );
          }
        }
    
        // If new component APIs are defined, "unsafe" lifecycles won't be called.
        // Warn about these lifecycles if they are present.
        // Don't warn about react-lifecycles-compat polyfilled methods though.
        if (
          typeof ctor.getDerivedStateFromProps === 'function' ||
          typeof instance.getSnapshotBeforeUpdate === 'function'
        ) {
          let foundWillMountName = null;
          let foundWillReceivePropsName = null;
          let foundWillUpdateName = null;
          if (
            typeof instance.componentWillMount === 'function' &&
            instance.componentWillMount.__suppressDeprecationWarning !== true
          ) {
            foundWillMountName = 'componentWillMount';
          } else if (typeof instance.UNSAFE_componentWillMount === 'function') {
            foundWillMountName = 'UNSAFE_componentWillMount';
          }
          if (
            typeof instance.componentWillReceiveProps === 'function' &&
            instance.componentWillReceiveProps.__suppressDeprecationWarning !== true
          ) {
            foundWillReceivePropsName = 'componentWillReceiveProps';
          } else if (
            typeof instance.UNSAFE_componentWillReceiveProps === 'function'
          ) {
            foundWillReceivePropsName = 'UNSAFE_componentWillReceiveProps';
          }
          if (
            typeof instance.componentWillUpdate === 'function' &&
            instance.componentWillUpdate.__suppressDeprecationWarning !== true
          ) {
            foundWillUpdateName = 'componentWillUpdate';
          } else if (typeof instance.UNSAFE_componentWillUpdate === 'function') {
            foundWillUpdateName = 'UNSAFE_componentWillUpdate';
          }
          if (
            foundWillMountName !== null ||
            foundWillReceivePropsName !== null ||
            foundWillUpdateName !== null
          ) {
            const componentName = getComponentName(ctor) || 'Component';
            const newApiName =
              typeof ctor.getDerivedStateFromProps === 'function'
                ? 'getDerivedStateFromProps()'
                : 'getSnapshotBeforeUpdate()';
            if (!didWarnAboutLegacyLifecyclesAndDerivedState.has(componentName)) {
              didWarnAboutLegacyLifecyclesAndDerivedState.add(componentName);
              warningWithoutStack(
                false,
                'Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n' +
                  '%s uses %s but also contains the following legacy lifecycles:%s%s%s\n\n' +
                  'The above lifecycles should be removed. Learn more about this warning here:\n' +
                  'https://fb.me/react-async-component-lifecycle-hooks',
                componentName,
                newApiName,
                foundWillMountName !== null ? `\n  ${foundWillMountName}` : '',
                foundWillReceivePropsName !== null
                  ? `\n  ${foundWillReceivePropsName}`
                  : '',
                foundWillUpdateName !== null ? `\n  ${foundWillUpdateName}` : '',
              );
            }
          }
        }
      }
    
      // Cache unmasked context so we can avoid recreating masked context unless necessary.
      // ReactFiberContext usually updates this cache but can't for newly-created instances.
      if (isLegacyContextConsumer) {
        cacheContext(workInProgress, unmaskedContext, context);
      }
    
      return instance;
    }
    
    • 进入 adoptClassInstance
      function adoptClassInstance(workInProgress: Fiber, instance: any): void {
        instance.updater = classComponentUpdater; // 挂载 update 方法
        workInProgress.stateNode = instance; // instance 挂载到 stateNode 以供下次进来时使用,下次进来就会存在了
        // The instance needs access to the fiber so that it can schedule updates
        ReactInstanceMap.set(instance, workInProgress);
        if (__DEV__) {
          instance._reactInternalInstance = fakeInternalInstance;
        }
      }
      
    • 进入 ReactInstanceMap 这个就是对 instance 上 _reactInternalFiber 属性的设置
      export function remove(key) {
        key._reactInternalFiber = undefined;
      }
      
      export function get(key) {
        return key._reactInternalFiber;
      }
      
      export function has(key) {
        return key._reactInternalFiber !== undefined;
      }
      
      export function set(key, value) {
        key._reactInternalFiber = value;
      }
      
      • 这也意味着,通过 this._reactInternalFiber 就可以拿到当前 fiber 对象
  • 进入 mountClassInstance

    // Invokes the mount life-cycles on a previously never rendered instance.
    function mountClassInstance(
      workInProgress: Fiber,
      ctor: any,
      newProps: any,
      renderExpirationTime: ExpirationTime,
    ): void {
      if (__DEV__) {
        checkClassInstance(workInProgress, ctor, newProps);
      }
      
      const instance = workInProgress.stateNode;
      instance.props = newProps;
      instance.state = workInProgress.memoizedState;
      instance.refs = emptyRefsObject;
    
      const contextType = ctor.contextType;
      if (typeof contextType === 'object' && contextType !== null) {
        instance.context = readContext(contextType);
      } else {
        const unmaskedContext = getUnmaskedContext(workInProgress, ctor, true);
        instance.context = getMaskedContext(workInProgress, unmaskedContext);
      }
    
      if (__DEV__) {
        if (instance.state === newProps) {
          const componentName = getComponentName(ctor) || 'Component';
          if (!didWarnAboutDirectlyAssigningPropsToState.has(componentName)) {
            didWarnAboutDirectlyAssigningPropsToState.add(componentName);
            warningWithoutStack(
              false,
              '%s: It is not recommended to assign props directly to state ' +
                "because updates to props won't be reflected in state. " +
                'In most cases, it is better to use props directly.',
              componentName,
            );
          }
        }
    
        if (workInProgress.mode & StrictMode) {
          ReactStrictModeWarnings.recordUnsafeLifecycleWarnings(
            workInProgress,
            instance,
          );
    
          ReactStrictModeWarnings.recordLegacyContextWarning(
            workInProgress,
            instance,
          );
        }
    
        if (warnAboutDeprecatedLifecycles) {
          ReactStrictModeWarnings.recordDeprecationWarnings(
            workInProgress,
            instance,
          );
        }
      }
    
      // 获取 updateQueue,初次渲染这个 updateQueue 是空的
      // 对于有 setState 的情况,它的 updateQueen 里面可能有多个update
      // 这个时候, 需要调用这个 updateQueen 来去得到一个新的state
      let updateQueue = workInProgress.updateQueue;
      if (updateQueue !== null) {
        // 这里 计算出新的state 并赋值给 workInProgress.memoizedState
        processUpdateQueue(
          workInProgress,
          updateQueue,
          newProps,
          instance,
          renderExpirationTime,
        );
        // 同时更新 instance.state
        instance.state = workInProgress.memoizedState;
      }
      
      // 判断是否有这个生命周期方法
      const getDerivedStateFromProps = ctor.getDerivedStateFromProps;
      if (typeof getDerivedStateFromProps === 'function') {
        // 如果存在该生命周期方法,则计算新的state
        // 这个生命周期会在组件更新的过程中被调用
        applyDerivedStateFromProps(
          workInProgress,
          ctor,
          getDerivedStateFromProps,
          newProps,
        );
        instance.state = workInProgress.memoizedState;
      }
    
      // In order to support react-lifecycles-compat polyfilled components,
      // Unsafe lifecycles should not be invoked for components using the new APIs.
      // 判断是否有 componentWillMount 生命周期方法
      // 在这个生命周期方法中,会执行 setState 方法
      if (
        typeof ctor.getDerivedStateFromProps !== 'function' &&
        typeof instance.getSnapshotBeforeUpdate !== 'function' &&
        (typeof instance.UNSAFE_componentWillMount === 'function' ||
          typeof instance.componentWillMount === 'function')
      ) {
        // 
        callComponentWillMount(workInProgress, instance);
        // If we had additional state updates during this life-cycle, let's
        // process them now.
        // 执行了 这个生命周期方法,就需要重新执行 updateQueue
        // 如果在这时执行了 setState, 立马被反映到组件上面
        updateQueue = workInProgress.updateQueue;
        if (updateQueue !== null) {
          processUpdateQueue(
            workInProgress,
            updateQueue,
            newProps,
            instance,
            renderExpirationTime,
          );
          instance.state = workInProgress.memoizedState;
        }
      }
    
      if (typeof instance.componentDidMount === 'function') {
        workInProgress.effectTag |= Update;
      }
    }
    
    • 进入 processUpdateQueue
      export function processUpdateQueue<State>(
        workInProgress: Fiber,
        queue: UpdateQueue<State>,
        props: any,
        instance: any,
        renderExpirationTime: ExpirationTime,
      ): void {
        hasForceUpdate = false;
        // 克隆 updateQueue
        queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue);
      
        if (__DEV__) {
          currentlyProcessingQueue = queue;
        }
      
        // These values may change as we process the queue.
        let newBaseState = queue.baseState;
        let newFirstUpdate = null;
        let newExpirationTime = NoWork;
      
        // Iterate through the list of updates to compute the result.
        let update = queue.firstUpdate; 
        let resultState = newBaseState;
        while (update !== null) {
          const updateExpirationTime = update.expirationTime;
          if (updateExpirationTime < renderExpirationTime) {
            // This update does not have sufficient priority. Skip it.
            if (newFirstUpdate === null) {
              // This is the first skipped update. It will be the first update in
              // the new list.
              newFirstUpdate = update;
              // Since this is the first update that was skipped, the current result
              // is the new base state.
              newBaseState = resultState;
            }
            // Since this update will remain in the list, update the remaining
            // expiration time.
            if (newExpirationTime < updateExpirationTime) {
              newExpirationTime = updateExpirationTime;
            }
          } else {
            // This update does have sufficient priority. Process it and compute
            // a new result.
            resultState = getStateFromUpdate(
              workInProgress,
              queue,
              update,
              resultState,
              props,
              instance,
            );
            const callback = update.callback;
            // 判断是否有 callback
            if (callback !== null) {
              workInProgress.effectTag |= Callback; // 加上 Callback 这块
              // Set this to null, in case it was mutated during an aborted render.
              update.nextEffect = null; // 防止在中断的渲染中被修改
              if (queue.lastEffect === null) {
                queue.firstEffect = queue.lastEffect = update; // 链表操作
              } else {
                queue.lastEffect.nextEffect = update;
                queue.lastEffect = update;
              }
            }
          }
          // Continue to the next update.
          update = update.next;
        }
      
        // Separately, iterate though the list of captured updates.
        let newFirstCapturedUpdate = null;
        update = queue.firstCapturedUpdate;
        while (update !== null) {
          const updateExpirationTime = update.expirationTime;
          if (updateExpirationTime < renderExpirationTime) {
            // This update does not have sufficient priority. Skip it.
            if (newFirstCapturedUpdate === null) {
              // This is the first skipped captured update. It will be the first
              // update in the new list.
              newFirstCapturedUpdate = update;
              // If this is the first update that was skipped, the current result is
              // the new base state.
              if (newFirstUpdate === null) {
                newBaseState = resultState;
              }
            }
            // Since this update will remain in the list, update the remaining
            // expiration time.
            if (newExpirationTime < updateExpirationTime) {
              newExpirationTime = updateExpirationTime;
            }
          } else {
            // This update does have sufficient priority. Process it and compute
            // a new result.
            resultState = getStateFromUpdate(
              workInProgress,
              queue,
              update,
              resultState,
              props,
              instance,
            );
            const callback = update.callback;
            if (callback !== null) {
              workInProgress.effectTag |= Callback;
              // Set this to null, in case it was mutated during an aborted render.
              update.nextEffect = null;
              if (queue.lastCapturedEffect === null) {
                queue.firstCapturedEffect = queue.lastCapturedEffect = update;
              } else {
                queue.lastCapturedEffect.nextEffect = update;
                queue.lastCapturedEffect = update;
              }
            }
          }
          update = update.next;
        }
      
        if (newFirstUpdate === null) {
          queue.lastUpdate = null;
        }
        if (newFirstCapturedUpdate === null) {
          queue.lastCapturedUpdate = null;
        } else {
          workInProgress.effectTag |= Callback;
        }
        if (newFirstUpdate === null && newFirstCapturedUpdate === null) {
          // We processed every update, without skipping. That means the new base
          // state is the same as the result state.
          newBaseState = resultState;
        }
      
        queue.baseState = newBaseState;
        queue.firstUpdate = newFirstUpdate;
        queue.firstCapturedUpdate = newFirstCapturedUpdate;
      
        // Set the remaining expiration time to be whatever is remaining in the queue.
        // This should be fine because the only two other things that contribute to
        // expiration time are props and context. We're already in the middle of the
        // begin phase by the time we start processing the queue, so we've already
        // dealt with the props. Context in components that specify
        // shouldComponentUpdate is tricky; but we'll have to account for
        // that regardless.
        workInProgress.expirationTime = newExpirationTime;
        workInProgress.memoizedState = resultState;
      
        if (__DEV__) {
          currentlyProcessingQueue = null;
        }
      }
      
      • 进入 ensureWorkInProgressQueueIsAClone
      function ensureWorkInProgressQueueIsAClone<State>(
        workInProgress: Fiber,
        queue: UpdateQueue<State>,
      ): UpdateQueue<State> {
        const current = workInProgress.alternate;
        if (current !== null) {
          // If the work-in-progress queue is equal to the current queue,
          // we need to clone it first.
          if (queue === current.updateQueue) {
            // 要保证 workInProgress.updateQueue 是一个克隆的queue, 而非直接进行修改
            queue = workInProgress.updateQueue = cloneUpdateQueue(queue); // 拷贝 queue
          }
        }
        return queue;
      }
      
    • 进入 getStateFromUpdate
      function getStateFromUpdate<State>(
        workInProgress: Fiber,
        queue: UpdateQueue<State>,
        update: Update<State>,
        prevState: State,
        nextProps: any,
        instance: any,
      ): any {
        switch (update.tag) {
          case ReplaceState: {
            const payload = update.payload;
            if (typeof payload === 'function') {
              // Updater function
              if (__DEV__) {
                if (
                  debugRenderPhaseSideEffects ||
                  (debugRenderPhaseSideEffectsForStrictMode &&
                    workInProgress.mode & StrictMode)
                ) {
                  payload.call(instance, prevState, nextProps);
                }
              }
              return payload.call(instance, prevState, nextProps);
            }
            // State object
            return payload;
          }
          // 这里 a & ~b 表示: a & 除了b之外的所有属性
          case CaptureUpdate: {
            workInProgress.effectTag =
              (workInProgress.effectTag & ~ShouldCapture) | DidCapture; // 这里最终剩下的 只有 DidCapture
          }
          // Intentional fallthrough
          case UpdateState: {
            const payload = update.payload;
            let partialState;
            if (typeof payload === 'function') {
              // Updater function
              if (__DEV__) {
                if (
                  debugRenderPhaseSideEffects ||
                  (debugRenderPhaseSideEffectsForStrictMode &&
                    workInProgress.mode & StrictMode)
                ) {
                  payload.call(instance, prevState, nextProps);
                }
              }
              // 如果是 function 则调用 payload 传入之前的参数 计算出 state
              partialState = payload.call(instance, prevState, nextProps);
            } else {
              // Partial state object
              partialState = payload;
            }
            // 处理特殊情况
            if (partialState === null || partialState === undefined) {
              // Null and undefined are treated as no-ops.
              return prevState;
            }
            // Merge the partial state and the previous state.
            // 合并
            return Object.assign({}, prevState, partialState);
          }
          case ForceUpdate: {
            hasForceUpdate = true;
            return prevState;
          }
        }
        return prevState;
      }
      
  • 进入 finishClassComponent

    function finishClassComponent(
      current: Fiber | null,
      workInProgress: Fiber,
      Component: any,
      shouldUpdate: boolean,
      hasContext: boolean,
      renderExpirationTime: ExpirationTime,
    ) {
      // Refs should update even if shouldComponentUpdate returns false
      // 这个先跳过
      markRef(current, workInProgress);
    
      // 判断 workInProgress.effectTag 上是否有 DidCapture
      const didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect;
      // 在没有更新也没有错误捕获的情况下
      if (!shouldUpdate && !didCaptureError) {
        // Context providers should defer to sCU for rendering
        if (hasContext) {
          invalidateContextProvider(workInProgress, Component, false);
        }
        // 跳过更新
        return bailoutOnAlreadyFinishedWork(
          current,
          workInProgress,
          renderExpirationTime,
        );
      }
    
      const instance = workInProgress.stateNode;
    
      // Rerender
      ReactCurrentOwner.current = workInProgress;
      let nextChildren;
      // 有任何错误捕获, 但没有配置这个api的时候
      // 这个 getDerivedStateFromError 生命周期的api和 componentDidCatch 有区别, 后者在下次更新的时候处理,中间可能instance不存在(因为出错了)
      // 就继续可能引发在这个class component上面设置的 ref拿到一个null, 操作ref的时候就会出现错误
      // 在前者这个新的生命周期的api中, 在本次渲染中,生成 state, 渲染出属性, 这样对于 instance 对象依然存在 对应 ref 就可以拿到实际的对象
      if (
        didCaptureError &&
        typeof Component.getDerivedStateFromError !== 'function'
      ) {
        // If we captured an error, but getDerivedStateFrom catch is not defined,
        // unmount all the children. componentDidCatch will schedule an update to
        // re-render a fallback. This is temporary until we migrate everyone to
        // the new API.
        // TODO: Warn in a future release.
        nextChildren = null;
    
        if (enableProfilerTimer) {
          stopProfilerTimerIfRunning(workInProgress);
        }
      } else {
        if (__DEV__) {
          ReactCurrentFiber.setCurrentPhase('render');
          nextChildren = instance.render();
          if (
            debugRenderPhaseSideEffects ||
            (debugRenderPhaseSideEffectsForStrictMode &&
              workInProgress.mode & StrictMode)
          ) {
            instance.render();
          }
          ReactCurrentFiber.setCurrentPhase(null);
        } else {
          // 调用 render 方法,计算出新的 children
          nextChildren = instance.render();
        }
      }
    
      // React DevTools reads this flag.
      workInProgress.effectTag |= PerformedWork; // 增加 PerformedWork
      // 不是第一次渲染,并且有错误捕获
      if (current !== null && didCaptureError) {
        // If we're recovering from an error, reconcile without reusing any of
        // the existing children. Conceptually, the normal children and the children
        // that are shown on error are two different sets, so we shouldn't reuse
        // normal children even if their identities match.
        forceUnmountCurrentAndReconcile(
          current,
          workInProgress,
          nextChildren,
          renderExpirationTime,
        );
      } else {
        // 正常情况调用 调和 children
        reconcileChildren(
          current,
          workInProgress,
          nextChildren,
          renderExpirationTime,
        );
      }
    
      // Memoize state using the values we just used to render.
      // TODO: Restructure so we never read values from the instance.
      workInProgress.memoizedState = instance.state;
    
      // The context might have changed so we need to recalculate it.
      if (hasContext) {
        invalidateContextProvider(workInProgress, Component, true);
      }
    
      return workInProgress.child; // 把 render 方法渲染出来的第一个子节点 返回给 nextUnitOfWork, 就可以在 workLoop 中继续进行更新的流程
    }
    
  • 简单总结

    • 以上是更新 class component 的整体流程
    • 一开始要使用 constructClassInstance 创建 class instance
    • 内部会根据不同情况调用不同方法
    • 并且要调用 mountClassInstance 来挂载
    • 如果是第一次渲染被中断的情况
      • 如果存在 instance 则重复使用 instance
      • 它调用的生命周期方法仍然是 第一次渲染的生命周期方法
      • 也就是 componentDidMount
    • 如果不是第一次渲染的情况
      • 调用 updateClassInstance 方法
      • 这种会最终调用 componentDidUpdate 方法
    • 它们中间的流程类似
      • 判断各种情况,创建新的 instance 或 复用之前的
      • 通过 processUpdateQueue 来获取新的 state
      • 会把它赋值到 instance 和 fiber 上面进行记录
      • 最终都会调用 finishClassComponent
        • 这里面做一些错误判断的处理
        • 以及是否可以跳过更新的过程
        • 还有重新调和子节点 (通用流程)
React高级备忘录(生命周期)class component 什么是生命周期?就像人有生老病死,component也有类似这样的概念,了解生命周期可以让我们知道如何在「对」的时间做「对」的事。 — Lieutenant过!constructor :初始化 static getDerivedStateFromProps componentWillMount(即将废弃 render :渲染 componentDidMount: DOM挂载完成componentWillReceiveProps :props改变时才触发(即将废弃 static getDerivedState 阅读详情

相关推荐

react-class-component:类组件是定义React组件的一种更有特色的方式

React类组件 类组件是定义React组件的一种更有特色的方式。 它也像接收道具的函数一样工作,但是该函数还将私有内部状态视为控制返回的JSX#react-class-component的附加输入。

学习React(6) - Class 组件(Component)

博主将继续学习React, 如果用class 这个关键字来做组件的话,应该如何来实现呢!之前是在App.js 文件里用class component, 现在就不在App.js 文件里实现。 就直接上代码,还是一样在src文件夹里,创建一个文件: // 这是Testclasscomponent.js 文件 // 使用Class Component来写的 import React, {Component} from 'react'; class Testclass extends Component{

CHNMSCS 1192

Cesium实战:从DEM数据到3D地形可视化的全流程解析

本文详细解析了从DEM数据到3D地形可视化的全流程,重点介绍了Cesium和Cesiumlab在数字高程模型(DEM)处理与地形数据转换中的应用。通过实战案例和工具对比,帮助开发者高效实现地形可视化,并分享性能优化与高级功能开发经验。

weixin_29079743的博客 336

React:Component组件

组件允许开发者将复杂的UI页面拆分为独立可复用的代码片段,并对每个代码片段进行独立构思。React中的组件,在概念上类似于JavaScript函数,它接收任意的入参(对应当该组件的props属性),返回值为描述页面区块内容的React Virtual DOM-虚拟DOM元素或者元素的集合。 React框架允许开发者定义两种基本组件:①函数式组件,本质上就是一个JavaScript函数;②Class类式组件,基于ES6的class类语法,结合extends继承机制实现组件实例的定义。

席木木的博客 2609

利用 Docker Distribution 搭建私有的 Docker Registry

1、拓扑

weixin_44983653的博客 1068

快充协议全兼容!HUSB390对比测试:iPhone/小米/华为哪个充电最快?

本文深入评测了HUSB390快充协议芯片的全兼容性能,展示了其在iPhone、小米和华为设备上的极速充电表现。通过智能功率分配算法和多协议并行处理引擎,HUSB390实现了高效的动态调压和温度控制,显著提升多设备充电效率。特别适合需要同时为不同品牌设备快充的用户。

dd012的博客 1万+

react hooks 实践总结(一):class component 和 function component

自从我深入了解了 react hooks,被其简洁的编写方式和强大的扩展性深深吸引,然后我就迫不及待地想把它应用到实际项目中。 使用下来发现,真香!但是坑也不少。react hooks 使用起来代码确实简洁不少,甚至说有点黑魔法的味道。如果使用者不怎么了解 hooks 实现原理和函数组件的渲染过程,很容易导致使用 hooks 编写组件时出现一些很离奇的 bug,所以使用好 hooks 还是需要一定...

qq_39523606的博客 554

Isaac Sim 使用经验(配置要求,云服务器)

Google Colab及AutoDL都是在docker内运行,其中google colab并不支持docker指令,而依照AutoDL的相关文档,AutoDL并不直接提供docker指令。2. Google Colab/AutoDL 不支持图形化界面,图形渲染等任务,所以没有办法使用Omniverse Streaming进行直播,从而更好的对结果进行展示。对于第一点,或许存在直接手动复现镜像的可能,但是考虑到Isaac Sim/Isaac Lab由于比较新,可能不够稳定,因此还是按照官方文档进行部署。

weixin_44211433的博客 4591

React函数组件和类组件的区别

定义组件名的要求: 组件名称必须以大写字母开头 组件的返回值只能有一个根元素 函数组件 function Welcome (props) { return <h1>Welcome {props.name}</h1> } ReactDOM.render(<Welcome name='react' />, document.getElementById('root')); ...

m0_48205289的博客 2423

开源Agent Skill让AI画图不再翻车:从数据到专业图表全流程

在人工智能与数据可视化交叉领域,让模型直接生成图表往往伴随字体乱码、坐标轴密集、配色失调等高频问题。Agent Skill作为一种可复用的能力封装机制,将专业绘图流程固化为标准化操作手册,从数据特征识别、图表类型决策到代码生成与渲染校验形成完整闭环。它不再依赖临时提示词的一次性发挥,而是让AI按领域专家的思维执行任务,显著提升出图质量与稳定性。这种能力在数据分析报告、运营日报、论文插图等场景具有广泛实用价值,尤其适用于需要快速产出规范化图表的工作流。本文即从这一技术范式出发,介绍一个GitHub上获得2.5

weixin_33851429的博客 992

Android Qcom USB Driver学习(五)

在前面的第二期中,我们知道一些非标的USB的充电类型Floatingcharger,其具有和普通DCP相似的大电流能力,但在最初检测的时候会限制Inputcurrentlimit到100mA,来进行检测是否是SDP类型,所以要支持大电流输入就需要进行vote操作,前面的几篇都有涉及,所以本文学习一下pmicusbcharger都相关的vote机制。...

Android驱动开发 2902

react源码解析-debugger阶段-类组件mount阶段的beginWork

类组件的beginWork。 Appfiber执行完递阶段之后,轮到DDfiber执行递解端。 对于类组件,在beginWork的时候,会调用updateClassComponent方法。 类组件的fiber如: { alternate: null child: null elementType: ƒ DD() key: null lanes: 16 mode: 1 pendingProps: {} ref: null return: FiberNode {tag: 0, key: null, stateN

lin_fightin的博客 1213

SerDes电路的PCB仿真设计规则及策略

SerDes的PCB设计中,重点工作是使用3D 电磁 (EM) 场求解器,进行过孔结构优化,包括 BGA的扇入和扇出区域以及布线的过孔区域,并且,利用连接器供应商提供加密的 3D 模型,进行连接器和 PCB 的级联仿真,最终获取系统级的通道性能参数,如插入损耗、回波损耗、串扰和模式转换、阻抗曲线等,如果发现任何缺陷,再进行进一步优化,这一过程中,推荐进行拆分仿真,以提高设计效率。

一只豌豆象的博客 2193

使用React class component(类组件)实现购物车复选框全选/全不选功能

在使用React的过程中,复选框当全选按钮处于选择状态,所有子项按钮也是处于选择状态,反之,当全选按钮处于未选中状态,所有子项也都处于未选中状态。当子项所有按钮全部选中时,全选按钮也会随之自动选中,如果子项有一个没有被选中,全选按钮就不会被选中...

weixin_71669449的博客 1385

SAP录入总账凭证报错 公司代码未被分配给国家或用于计算程序的国家消息号 FF703

SAP系统报错FF703的解决方案:当公司代码未分配国家或未配置计税程序时,会导致增值税计算失败。处理方法:1)通过OX02检查公司代码国家字段;2)使用OBBG为国家分配计税程序(如TAXCN)。配置步骤:1)SPRO分配公司代码到国家;2)OBBG设置国家对应的计税程序。注意事项:历史数据需清理才能修改国家字段,不同账簿可配置不同计税程序。完成配置后即可正常处理含税凭证。

金牌架构师 560

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

【React】class类组件

1. getDerivedStateFromProps 存在的目的只有一个:让组件在props 变化时更新 state。true则执行后续流程,false则不执行**出现之前,类组件是实现状态和生命周期逻辑的主要方式,它们具备更复杂的功能。组件初始化时的构造函数,只执行一次,需要显示调用 super(props)组件接收到新的属性调用,返回一个对象,该对象会合并到state中。组件挂载完成后调用,使用场景:网络请求、获取dom、设置事件监听等。在更新之前获取state的快照,此时可以获取dom信息。

zww学习笔记 466

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

React--Component组件浅析

在 React 世界里,一切皆组件,我们写的 React 项目全部起源于组件。组件可以分为两类,一类是类( Class )组件,一类是函数( Function )组件。本章节,我们将一起探讨 React 中类组件和函数组件的定义,不同组件的通信方式,以及常规组件的强化方式,帮助你全方位认识 React 组件,从而对 React 的底层逻辑有进一步的理解。想要理解 React 组件是什么?我们首先要来分析一下组件和常规的函数和类到底有什么本质的区别。/* 类 */ class textClass {

江拥羡橙的博客 3933

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

如何用 Hooks 来实现 React Class Component 写法?

Hooks 的 API 可以参照 React 官网。本文主要是结合 Demo 详细讲解如何用 Hooks 来实现 React Class Component 写法,让大家更深的理解 Hooks 的机制并且更快的入门。注意:Rax 的写法和 React 是一致的,本文 Demo 基于 React 实现,查看 Demo 完整版 本文内容包括如下:一、在 Hooks 中如何实现 Class Compon...

天涯游子 2076

React组件三大类:类组件、函数组件、高阶组件

本文将详细介绍React中的类组件、函数组件和高阶组件,帮助读者理解它们的概念、使用场景和优势,以便在实际项目中合理选择和使用。类组件、函数组件和高阶组件是React中三种常见的组件类型,它们各自具有独特的特点和优势。掌握这三种组件类型的使用方法,可以根据实际需求在项目中合理选择和使用。

你若盛开,清风自来 2625

React学习笔记 - 基础概念(三) ClassComponent生命周期

生命周期图谱 https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/ 挂载 当组件实例被创建并插入 DOM 中时,其生命周期调用顺序如下: constructor() static getDerivedStateFromProps() render() componentDidMount() 注意: 下述生命周期方法即将过时,在新代码中应该避免使用它们: UNSAFE_compone

倾听风的声音,跟随风的脚步! 445

React class & function component 的区别

学习react之理解 React class & function component区别 本文参考自 https://www.cnblogs.com/chrissong/p/10445191.html function component function Welcome(props) { return <h1>Hello, {props.name}</h1&g...

日常编码 607

react中的类(有状态)组件,函数(无状态)组件·示例,对比及组件样式引用方案(附代码)

3. 无状态函数组件(Stateless Functional Components):无状态函数组件是函数组件的一种特殊形式,它们没有内部状态(state)。在类组件中,通过构造函数(constructor)来初始化内部状态,通过生命周期方法(componentDidMount、componentDidUpdate、componentWillUnmount等)来进行特定的操作(例如发起网络请求、订阅/取消订阅事件等),通过渲染方法(render)来返回一个React元素来描述组件的输出。

kkkys_kkk的博客 2148

React类组件详解

React类组件是通过创建class继承React.Component来创建的,是React中用于构建用户界面的重要部分。以下是对React类组件的详细解释:一、定义与基本结构类组件使用ES6的class语法定义,并继承自React.Component。它们具有更复杂的功能,特别是在React 16.8之前,是唯一能够使...

Java_fenxiang的博客 1429

React-class component 和 function component 的区别

1、function component: function aa(props) { return <h1>this is {props.name}</h1> } 2、class component: class bb extends React.Component { render() { const { name } = this.props; retur...

qq_24917475的博客 1850

React.Component (React class 组件的详细 API 参考)

本章节提供了 React class 组件的详细 API 参考。本章节默认你已熟悉基本的 React 概念,例如 组件 & Props,以及 State & 生命周期等。如果你还未熟悉,请先阅读之前章节进行学习。 React 的组件可以定义为 class 或函数的形式。class 组件目前提供了更多的功能,这些功能将在此章节中详细介绍。如需定义 class 组件,需要继承 React.Component: class Welcome extends React.Component { r

qq_42420970的博客 1201

React-Class-Component-lifecycle

react类组件生命周期: 阶段:挂载、更新、卸载 不同阶段需要做不同的事情(状态初始化、this批量绑定、网络数据请求、DOM操作...) 在不同阶段不同的钩子函数里面去做 两个概念 语法糖: 便捷写法,编译后和之前一样,糖在不改变其所在位置的语法结构的前提下,实现了运行时等价 function与class 01.挂载阶段:将创建的组件-真实DOM-插入容器 ...

u013745284的博客 212
上一篇: React16源码: React中的reconcileChildIterator和reconcileChildrenArray的源码实现
下一篇: React16源码: React中的IndeterminateComponent的源码实现
Wang's Blog
博客等级 码龄12年 7438粉丝 2421原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值