worKTags用于标识当前的fiber。
//packages\shared\ReactWorkTags.js
export const FunctionComponent = 0;
export const ClassComponent = 1;
export const IndeterminateComponent = 2; // Before we know whether it is function or class
export const HostRoot = 3; // Root of a host tree. Could be nested inside another node.
export const HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
export const HostComponent = 5;
export const HostText = 6;
export const Fragment = 7;
export const Mode = 8;
export const ContextConsumer = 9;
export const ContextProvider = 10;
export const ForwardRef = 11;
export const Profiler = 12;
export const SuspenseComponent = 13;
export const MemoComponent = 14;
export const SimpleMemoComponent = 15;
export const LazyComponent = 16;
export const IncompleteClassComponent = 17;
createFiberFromElement
workLoop中会创建React Tree,常用的创建createFiberFromElement。
export function createFiberFromElement(
element: ReactElement,
mode: TypeOfMode,
expirationTime: ExpirationTime,
): Fiber {
let owner = null;
if (__DEV__) {
owner = element._owner;
}
const type = element.type;
const key = element.key;
const pendingProps = element.props;
const fiber = createFiberFromTypeAndProps(
type,
key,
pendingProps,
owner,
mode,
expirationTime,
);
if (__DEV__) {
fiber._debugSource = element._source;
fiber._debugOwner = element._owner;
}
return fiber;
}
此处的element为ReactElement,使用 createFiberFromTypeAndProps 创建fiber时会根据ReactElement的type,赋予不同的fiberTag。
export function createFiberFromTypeAndProps(
type: any, // React$ElementType
key: null | string,
pendingProps: any,
owner: null | Fiber,
mode: TypeOfMode,
expirationTime: ExpirationTime,
): Fiber {
let fiber;
let fiberTag = IndeterminateComponent;
// The resolved type is set if we know what the final type will be. I.e. it's not lazy.
let resolvedType = type;
if (typeof type === 'function') {
if (shouldConstruct(type)) {
fiberTag = ClassComponent;
}
} else if (typeof type === 'string') {
fiberTag = HostComponent;
} else {
getTag: switch (type) {
case REACT_FRAGMENT_TYPE:
return createFiberFromFragment(
pendingProps.children,
mode,
expirationTime,
key,
);
case REACT_CONCURRENT_MODE_TYPE:
return createFiberFromMode(
pendingProps,
mode | ConcurrentMode | StrictMode,
expirationTime,
key,
);
case REACT_STRICT_MODE_TYPE:
return createFiberFromMode(
pendingProps,
mode | StrictMode,
expirationTime,
key,
);
case REACT_PROFILER_TYPE:
return createFiberFromProfiler(pendingProps, mode, expirationTime, key);
case REACT_SUSPENSE_TYPE:
return createFiberFromSuspense(pendingProps, mode, expirationTime, key);
default: {
if (typeof type === 'object' && type !== null) {
switch (type.$$typeof) {
case REACT_PROVIDER_TYPE:
fiberTag = ContextProvider;
break getTag;
case REACT_CONTEXT_TYPE:
// This is a consumer
fiberTag = ContextConsumer;
break getTag;
case REACT_FORWARD_REF_TYPE:
fiberTag = ForwardRef;
break getTag;
case REACT_MEMO_TYPE:
fiberTag = MemoComponent;
break getTag;
case REACT_LAZY_TYPE:
fiberTag = LazyComponent;
resolvedType = null;
break getTag;
}
}
}
}
}
fiber = createFiber(fiberTag, pendingProps, key, mode);
fiber.elementType = type;
fiber.type = resolvedType;
fiber.expirationTime = expirationTime;
return fiber;
}
IndeterminateComponent
根据ReactElement的type定fiber 的tag。此处function需要注意,若是type是function,不是ClassComponent,则为IndeterminateComponent 。
if (typeof type === 'function') {
if (shouldConstruct(type)) {
fiberTag = ClassComponent;
}
}
HostComponent
字符串类型的’span’、’div’、’p’等,都为 HostComponent。当reconciler 遇到 host element时,它让 renderer 负责挂载它。
Fragment
React还提供了一个组件,可以在不使用包装器的情况下呈现多个元素。
render() {
return (
<React.Fragment>
Some text.
<h2>A heading</h2>
</React.Fragment>
);
}
ContextConsumer
ContextConsumer 是Context.Consumer。
ContextProvider
ContextProvider 是 Context.Provider。
ForwardRef
Profiler
一个性能检测工具。
- with-the-devtools-profiler
- introducing-the-react-profiler
SuspenseComponent
React增加React.lazy之后,可以异步加载组件。例如:const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<OtherComponent />
</div>
);
}
如果这样写,在加载期间,我们必须显示一些内容,例如loading组件,这时就需要使用Suspense component。改写后的例子:
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
</div>
);
}
当然也可以在Suspense 中包含多个异步加载的组件,例如:
const OtherComponent = React.lazy(() => import('./OtherComponent'));
const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<OtherComponent />
<AnotherComponent />
</section>
</Suspense>
</div>
);
}
MemoComponent、SimpleMemoComponent
React.memo 是一个高阶组件。它类似于React.PureComponent,但用于函数组件而不是类。
const MyComponent = React.memo(function MyComponent(props) {
/* render using props */
});
如果你的函数组件在给定相同的道具的情况下呈现相同的结果,则可以React.memo通过记忆结果将其包装在一些调用中以提高性能。这意味着React将跳过渲染组件,并重用最后渲染的结果。
默认情况下,它只会浅显比较props对象中的复杂对象。如果要控制比较,还可以提供自定义比较函数作为第二个参数。
function MyComponent(props) {
/* render using props */
}
function areEqual(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
}
export default React.memo(MyComponent, areEqual);
LazyComponent
注意::React.lazy and Suspense 暂时不支持服务端渲染。 React.lazy可以将动态导入呈现为常规组件。