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))
resolveLazyComponentTag是ReactFiber提供的根据特性判断组件类型的方法,可以判断是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方法,resolve和reject之后会分别设置_status和_result,默认_status变成pendding,所以下一次进来会throw thenable,这就进入了Suspense的阶段了。
results matching ""
No results matching ""
扫码添加Jokcy,更多更新更优质的前端学习内容不断更新中,期待与你一起成长!