制作商城网站公司,网站内容的作用,数码网站建设维护,可以用手机制作app的软件IndeterminateComponent 1 #xff09;概述
这是一个比较特殊的component的类型#xff0c; 就是还没有被指定类型的component在一个fibrer被创建的时候#xff0c;它的tag可能会是 IndeterminateComponent在 packages/react-reconciler/src/ReactFiber.js 中#xff0c;有…IndeterminateComponent 1 概述
这是一个比较特殊的component的类型 就是还没有被指定类型的component在一个fibrer被创建的时候它的tag可能会是 IndeterminateComponent在 packages/react-reconciler/src/ReactFiber.js 中有一个方法createFiberFromTypeAndProps 中一开始就声明了let fiberTag IndeterminateComponent;
let resolvedType type;
// 一开始
if (typeof type function) {// 在 function 下只是判断了 constructor是否存在// 在不存在的时候是否认为它是一个 FunctionComponent 呢实际上并没有// 实际上我们写的任何一个 function component 一开始就是 IndeterminateComponent 类型if (shouldConstruct(type)) {// 存在则赋值为 ClassComponentfiberTag 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 effectworkInProgress.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 doesnt 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 instanceworkInProgress.tag ClassComponent; // 这里认为它是一个 ClassComponent// Throw out any hooks that were used.resetHooks();// Push context providers early to prevent context stack mismatches.// During mounting we dont know the child context yet as the instance doesnt 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 componentworkInProgress.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;}
}基于上述判断条件 能认定是一个 ClassComponent后续渲染一定会按照 ClassComponent 进行 if ( typeof value object value ! null typeof value.render function value.$$typeof undefined ){} 现在来测试一下看下 function component 是否可以执行import React from reactexport default function TestIndeterminationComponent() {return {componentDidMount() {console.log(invoker)},render() {return spanaaa/span}}
}上述都能正常显示以及打印 console 输出也就是说对于一个 function component, 如果里面 return 的对象具有 render 方法就认为它是一个 class component 一样的类型去使用它并且在里面声明的生命周期方法都会被它调用这是 IndeterminateComponent 的特性 在最初我们渲染的时候所有的 function component 都是 IndeterminateComponent 的类型在第一次渲染之后我们根据渲染类型的返回最终得到具体类型可以通过 function component 返回一个对象的方式去渲染一个类似 classComponent 这样的类型注意一般不推荐这么写