lazy component

通过React.lazy我们非常方便地实现异步加载模块的功能,通过这个 API 创建的对象如下:

{
  $$typeof: REACT_LAZY_TYPE,
  _ctor: ctor,
  // React uses these fields to store the result.
  _status: -1,
  _result: null,
}

其中_status_result两个值是非常重要的,用来标记加载完成的模块的内容,而_ctor则记载了我们传入的生产thenable对象的方法。

在更新过程中,我们遇到lazy组件会怎么样呢?

function mountLazyComponent(
  _current,
  workInProgress,
  elementType,
  updateExpirationTime,
  renderExpirationTime,
) {
  if (_current !== null) {
    _current.alternate = null
    workInProgress.alternate = null
    workInProgress.effectTag |= Placement
  }

  const props = workInProgress.pendingProps
  cancelWorkTimer(workInProgress)
  let Component = readLazyComponentType(elementType)
  workInProgress.type = Component
  const resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component))
  startWorkTimer(workInProgress)
  const resolvedProps = resolveDefaultProps(Component, props)
  let child
  switch (resolvedTag) {
    // 根据返回的组件类型执行更新
    default: {
      // warning
    }
  }
  return child
}

首先我们看到如果_current存在值会强行删除current的引用,为什么要这么做呢?因为lazy组件只有在第一次渲染的时候才会调用该方法,等到组件已经加载完成了,就会走直接更新组件的流程,具体证据就是下面这句代码:

const resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component))

resolveLazyComponentTagReactFiber提供的根据特性判断组件类型的方法,可以判断是ClassComponent还是FunctionalComponent还是一些内置类型。在组件加载完成之后,就直接设置tag为新的类型了,并且设置了type为返回的Component,就变成了异步加载过来的组件了。

那么如果还没加载完成呢?我们来看readLazyComponentType

export const Pending = 0
export const Resolved = 1
export const Rejected = 2

export function readLazyComponentType<T>(lazyComponent: LazyComponent<T>): T {
  const status = lazyComponent._status
  const result = lazyComponent._result
  switch (status) {
    case Resolved: {
      const Component: T = result
      return Component
    }
    case Rejected: {
      const error: mixed = result
      throw error
    }
    case Pending: {
      const thenable: Thenable<T, mixed> = result
      throw thenable
    }
    default: {
      lazyComponent._status = Pending
      const ctor = lazyComponent._ctor
      const thenable = ctor()
      thenable.then(
        moduleObject => {
          if (lazyComponent._status === Pending) {
            const defaultExport = moduleObject.default
            lazyComponent._status = Resolved
            lazyComponent._result = defaultExport
          }
        },
        error => {
          if (lazyComponent._status === Pending) {
            lazyComponent._status = Rejected
            lazyComponent._result = error
          }
        },
      )
      lazyComponent._result = thenable
      throw thenable
    }
  }
}

这里就用到了_status_result,一开始_status-1,所以不符合前三个case,然后就进入default,这里面调用了_ctor创建了thenable对象,调用then方法,resolvereject之后会分别设置_status_result,默认_status变成pendding,所以下一次进来会throw thenable,这就进入了Suspense的阶段了。

results matching ""

    No results matching ""