React Fiber 热重载
一、作用
二、设置刷新处理程序
export const setRefreshHandler = (handler: RefreshHandler | null): void => {
if (__DEV__) {
resolveFamily = handler;
}
};
三、为热重载解析函数
export function resolveFunctionForHotReloading(type: any): any {
if (__DEV__) {
if (resolveFamily === null) {
// Hot reloading is disabled.
// 热更新已禁用。
return type;
}
const family = resolveFamily(type);
if (family === undefined) {
return type;
}
// Use the latest known implementation.
// 使用已知的最新实现。
return family.current;
} else {
return type;
}
}
四、 为热重载解析类
export function resolveClassForHotReloading(type: any): any {
// No implementation differences.
// 没有实现差异。
return resolveFunctionForHotReloading(type);
}
五、为热重载解析前向引用
export function resolveForwardRefForHotReloading(type: any): any {
if (__DEV__) {
if (resolveFamily === null) {
// Hot reloading is disabled.
// 热更新已禁用。
return type;
}
const family = resolveFamily(type);
if (family === undefined) {
// Check if we're dealing with a real forwardRef. Don't want to crash early.
// 检查我们是否在处理一个真正的 forwardRef。不要过早崩溃。
if (
type !== null &&
type !== undefined &&
typeof type.render === 'function'
) {
// ForwardRef is special because its resolved .type is an object,
// but it's possible that we only have its inner render function in the map.
// If that inner render function is different, we'll build a new forwardRef type.
//
// ForwardRef 很特别,因为它解析后的 .type 是一个对象,
// 但有可能我们在映射中只拥有它的内部渲染函数。
// 如果那个内部渲染函数不同,我们将构建一个新的 forwardRef 类型。
const currentRender = resolveFunctionForHotReloading(type.render);
if (type.render !== currentRender) {
const syntheticType = {
$$typeof: REACT_FORWARD_REF_TYPE,
render: currentRender,
};
if (type.displayName !== undefined) {
(syntheticType as any).displayName = type.displayName;
}
return syntheticType;
}
}
return type;
}
// Use the latest known implementation.
// 使用已知的最新实现。
return family.current;
} else {
return type;
}
}
六、 是否兼容热重载的组件
export function isCompatibleFamilyForHotReloading(
fiber: Fiber,
element: ReactElement,
): boolean {
if (__DEV__) {
if (resolveFamily === null) {
// Hot reloading is disabled.
// 热更新已禁用。
return false;
}
const prevType = fiber.elementType;
const nextType = element.type;
// If we got here, we know types aren't === equal.
// 如果我们到达这里,我们就知道类型不完全相等。
let needsCompareFamilies = false;
const $$typeofNextType =
typeof nextType === 'object' && nextType !== null
? nextType.$$typeof
: null;
switch (fiber.tag) {
case ClassComponent: {
if (typeof nextType === 'function') {
needsCompareFamilies = true;
}
break;
}
case FunctionComponent: {
if (typeof nextType === 'function') {
needsCompareFamilies = true;
} else if ($$typeofNextType === REACT_LAZY_TYPE) {
// We don't know the inner type yet.
// We're going to assume that the lazy inner type is stable,
// and so it is sufficient to avoid reconciling it away.
// We're not going to unwrap or actually use the new lazy type.
//
// 我们还不知道内部类型。
// 我们将假设懒惰的内部类型是稳定的,
// 因此只需避免将其调和掉即可。
// 我们不会解包或实际使用新的懒惰类型。
needsCompareFamilies = true;
}
break;
}
case ForwardRef: {
if ($$typeofNextType === REACT_FORWARD_REF_TYPE) {
needsCompareFamilies = true;
} else if ($$typeofNextType === REACT_LAZY_TYPE) {
needsCompareFamilies = true;
}
break;
}
case MemoComponent:
case SimpleMemoComponent: {
if ($$typeofNextType === REACT_MEMO_TYPE) {
// TODO: if it was but can no longer be simple,
// we shouldn't set this.
//
// 待办:如果它曾经可以,但现在不再简洁,
// 我们不应该设置它。
needsCompareFamilies = true;
} else if ($$typeofNextType === REACT_LAZY_TYPE) {
needsCompareFamilies = true;
}
break;
}
default:
return false;
}
// Check if both types have a family and it's the same one.
// 检查两种类型是否都有家庭,并且是否相同。
if (needsCompareFamilies) {
// Note: memo() and forwardRef() we'll compare outer rather than inner type.
// This means both of them need to be registered to preserve state.
// If we unwrapped and compared the inner types for wrappers instead,
// then we would risk falsely saying two separate memo(Foo)
// calls are equivalent because they wrap the same Foo function.
//
// 注意:我们将比较 memo() 和 forwardRef() 的外部类型,而不是内部类型。
// 这意味着两者都需要注册以保留状态。
// 如果我们解包并比较包装器的内部类型,
// 那么就有可能错误地认为两个独立的 memo(Foo) 调用是相同的,
// 因为它们包装的是相同的 Foo 函数。
const prevFamily = resolveFamily(prevType);
if (prevFamily !== undefined && prevFamily === resolveFamily(nextType)) {
return true;
}
}
return false;
} else {
return false;
}
}
七、为热加载标记失败的错误边界
export function markFailedErrorBoundaryForHotReloading(fiber: Fiber) {
if (__DEV__) {
if (resolveFamily === null) {
// Hot reloading is disabled.
// 热更新已禁用。
return;
}
if (typeof WeakSet !== 'function') {
return;
}
if (failedBoundaries === null) {
failedBoundaries = new WeakSet();
}
failedBoundaries.add(fiber);
}
}
八、 安排刷新
信息
flushPendingEffects()
export const scheduleRefresh: ScheduleRefresh = (
root: FiberRoot,
update: RefreshUpdate,
): void => {
if (__DEV__) {
if (resolveFamily === null) {
// Hot reloading is disabled.
// 热更新已禁用。
return;
}
const { staleFamilies, updatedFamilies } = update;
flushPendingEffects();
scheduleFibersWithFamiliesRecursively(
root.current,
updatedFamilies,
staleFamilies,
);
flushSyncWork();
}
};
变量
1.
// 解决家庭纠纷 (刷新处理程序)
let resolveFamily: RefreshHandler | null = null;
// 失败的边界
let failedBoundaries: WeakSet<Fiber> | null = null;