1 )概述
IndeterminateComponent
createFiberFromTypeAndProps
中,一开始就声明了let fiberTag = IndeterminateComponent;
let resolvedType = type;
// 一开始
if (typeof type === 'function') {
// 在 function 下只是判断了 constructor是否存在
// 在不存在的时候,是否认为它是一个 FunctionComponent 呢,实际上并没有
// 实际上我们写的任何一个 function component 一开始就是 IndeterminateComponent 类型
if (shouldConstruct(type)) {
// 存在,则赋值为 ClassComponent
fiberTag = ClassComponent;
}
} else if (typeof type === 'string') {
fiberTag = HostComponent;
} else {
// 省略
}
createFiber
创建 Fiber 对象2 )源码
定位到 packages/react-reconciler/src/ReactFiber.js
进入 mountIndeterminateComponent 方法
//
function mountIndeterminateComponent(
_current,
workInProgress,
Component,
renderExpirationTime,
) {
// 首先判断 _current 是否存在,存在则进行初始化操作
// 因为只有在第一次渲染的时候,才有 indeterminate component 这种情况
// 经过第一次渲染之后,我们就会发现 indeterminate component 的具体的类型
// 这种情况,可能是中途抛出一个 error 或 promise 等情况,比如 Suspense 组件
// 这时候初始化是为了 去除 _current 和 workInProgress 相关联系,因为需要重新进行初次渲染的流程
if (_current !== null) {
// An indeterminate component only mounts if it suspended inside a non-
// concurrent tree, in an inconsistent state. We want to treat 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;
}
const props = workInProgress.pendingProps;
const unmaskedContext = getUnmaskedContext(workInProgress, Component, false);
const context = getMaskedContext(workInProgress, unmaskedContext);
prepareToReadContext(workInProgress, renderExpirationTime);
prepareToUseHooks(null, workInProgress, renderExpirationTime);
let value;
if (__DEV__) {
if (
Component.prototype &&
typeof Component.prototype.render === 'function'
) {
const componentName = getComponentName(Component) || 'Unknown';
if (!didWarnAboutBadClass[componentName]) {
warningWithoutStack(
false,
"The <%s /> component appears to have a render method, but doesn't extend React.Component. " +
'This is likely to cause errors. Change %s to extend React.Component instead.',
componentName,
componentName,
);
didWarnAboutBadClass[componentName] = true;
}
}
if (workInProgress.mode & StrictMode) {
ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);
}
ReactCurrentOwner.current = workInProgress;
value = Component(props, context);
} else {
value = Component(props, context); // 调用 Component 方法
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
// 符合这个条件,认为是 ClassComponent, 具有 render 方法
if (
typeof value === 'object' &&
value !== null &&
typeof value.render === 'function' &&
value.$$typeof === undefined
) {
// Proceed under the assumption that this is a class instance
workInProgress.tag = ClassComponent; // 这里认为它是一个 ClassComponent
// Throw out any hooks that were used.
resetHooks();
// 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.
let hasContext = false;
if (isLegacyContextProvider(Component)) {
hasContext = true;
pushLegacyContextProvider(workInProgress);
} else {
hasContext = false;
}
workInProgress.memoizedState =
value.state !== null && value.state !== undefined ? value.state : null;
const getDerivedStateFromProps = Component.getDerivedStateFromProps;
if (typeof getDerivedStateFromProps === 'function') {
applyDerivedStateFromProps(
workInProgress,
Component,
getDerivedStateFromProps,
props,
);
}
adoptClassInstance(workInProgress, value);
mountClassInstance(workInProgress, Component, props, renderExpirationTime);
return finishClassComponent(
null,
workInProgress,
Component,
true,
hasContext,
renderExpirationTime,
);
} else {
// 否则按照 FunctionComponent 来渲染
// Proceed under the assumption that this is a function component
workInProgress.tag = FunctionComponent;
value = finishHooks(Component, props, value, context);
if (__DEV__) {
if (Component) {
warningWithoutStack(
!Component.childContextTypes,
'%s(...): childContextTypes cannot be defined on a function component.',
Component.displayName || Component.name || 'Component',
);
}
if (workInProgress.ref !== null) {
let info = '';
const ownerName = ReactCurrentFiber.getCurrentFiberOwnerNameInDevOrNull();
if (ownerName) {
info += '\n\nCheck the render method of `' + ownerName + '`.';
}
let warningKey = ownerName || workInProgress._debugID || '';
const debugSource = workInProgress._debugSource;
if (debugSource) {
warningKey = debugSource.fileName + ':' + debugSource.lineNumber;
}
if (!didWarnAboutFunctionRefs[warningKey]) {
didWarnAboutFunctionRefs[warningKey] = true;
warning(
false,
'Function components cannot be given refs. ' +
'Attempts to access this ref will fail.%s',
info,
);
}
}
if (typeof Component.getDerivedStateFromProps === 'function') {
const componentName = getComponentName(Component) || 'Unknown';
if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) {
warningWithoutStack(
false,
'%s: Function components do not support getDerivedStateFromProps.',
componentName,
);
didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true;
}
}
if (
typeof Component.contextType === 'object' &&
Component.contextType !== null
) {
const componentName = getComponentName(Component) || 'Unknown';
if (!didWarnAboutContextTypeOnFunctionComponent[componentName]) {
warningWithoutStack(
false,
'%s: Function components do not support contextType.',
componentName,
);
didWarnAboutContextTypeOnFunctionComponent[componentName] = true;
}
}
}
reconcileChildren(null, workInProgress, value, renderExpirationTime);
return workInProgress.child;
}
}
if ( typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined ){}
import React from 'react'
export default function TestIndeterminationComponent() {
return {
componentDidMount() {
console.log('invoker')
},
render() {
return <span>aaa</span>
}
}
}
IndeterminateComponent
的特性IndeterminateComponent
的类型