# unwindWork

completeWork其实差不多,最主要的区别是处理了ShouldCapture的副作用,这是在throwException的时候被添加的,只针对于有能力处理异常的ClassComponent或者直接到HostRoot

注意处理完ShouldCapture的组件都会增加DidCapture副作用并返回其Fiber对象,返回Fiber意味着在completeUnitOfWork中的next有值,则意味着当前组件需要重新走更新(beginWork)流程

function unwindWork(
  workInProgress: Fiber,
  renderExpirationTime: ExpirationTime,
) {
  switch (workInProgress.tag) {
    case ClassComponent: {
      const Component = workInProgress.type
      if (isLegacyContextProvider(Component)) {
        popLegacyContext(workInProgress)
      }
      const effectTag = workInProgress.effectTag
      if (effectTag & ShouldCapture) {
        workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture
        return workInProgress
      }
      return null
    }
    case HostRoot: {
      popHostContainer(workInProgress)
      popTopLevelLegacyContextObject(workInProgress)
      const effectTag = workInProgress.effectTag
      invariant(
        (effectTag & DidCapture) === NoEffect,
        'The root failed to unmount after an error. This is likely a bug in ' +
          'React. Please file an issue.',
      )
      workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture
      return workInProgress
    }
    case HostComponent: {
      popHostContext(workInProgress)
      return null
    }
    case SuspenseComponent: {
      const effectTag = workInProgress.effectTag
      if (effectTag & ShouldCapture) {
        workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture
        // Captured a suspense effect. Set the boundary's `alreadyCaptured`
        // state to true so we know to render the fallback.
        const current = workInProgress.alternate
        const currentState: SuspenseState | null =
          current !== null ? current.memoizedState : null
        let nextState: SuspenseState | null = workInProgress.memoizedState
        if (nextState === null) {
          // No existing state. Create a new object.
          nextState = {
            alreadyCaptured: true,
            didTimeout: false,
            timedOutAt: NoWork,
          }
        } else if (currentState === nextState) {
          // There is an existing state but it's the same as the current tree's.
          // Clone the object.
          nextState = {
            alreadyCaptured: true,
            didTimeout: nextState.didTimeout,
            timedOutAt: nextState.timedOutAt,
          }
        } else {
          // Already have a clone, so it's safe to mutate.
          nextState.alreadyCaptured = true
        }
        workInProgress.memoizedState = nextState
        // Re-render the boundary.
        return workInProgress
      }
      return null
    }
    case HostPortal:
      popHostContainer(workInProgress)
      return null
    case ContextProvider:
      popProvider(workInProgress)
      return null
    default:
      return null
  }
}