Best JavaScript code snippet using playwright-internal
ReactFiberBeginWork.new.js
Source:ReactFiberBeginWork.new.js
...543 nextProps,544 renderLanes,545 );546}547function updateOffscreenComponent(548 current: Fiber | null,549 workInProgress: Fiber,550 renderLanes: Lanes,551) {552 const nextProps: OffscreenProps = workInProgress.pendingProps;553 const nextChildren = nextProps.children;554 const prevState: OffscreenState | null =555 current !== null ? current.memoizedState : null;556 if (557 nextProps.mode === 'hidden' ||558 nextProps.mode === 'unstable-defer-without-hiding'559 ) {560 if ((workInProgress.mode & ConcurrentMode) === NoMode) {561 // In legacy sync mode, don't defer the subtree. Render it now.562 // TODO: Figure out what we should do in Blocking mode.563 const nextState: OffscreenState = {564 baseLanes: NoLanes,565 };566 workInProgress.memoizedState = nextState;567 pushRenderLanes(workInProgress, renderLanes);568 } else if (!includesSomeLane(renderLanes, (OffscreenLane: Lane))) {569 let nextBaseLanes;570 if (prevState !== null) {571 const prevBaseLanes = prevState.baseLanes;572 nextBaseLanes = mergeLanes(prevBaseLanes, renderLanes);573 } else {574 nextBaseLanes = renderLanes;575 }576 // Schedule this fiber to re-render at offscreen priority. Then bailout.577 if (enableSchedulerTracing) {578 markSpawnedWork((OffscreenLane: Lane));579 }580 workInProgress.lanes = workInProgress.childLanes = laneToLanes(581 OffscreenLane,582 );583 const nextState: OffscreenState = {584 baseLanes: nextBaseLanes,585 };586 workInProgress.memoizedState = nextState;587 // We're about to bail out, but we need to push this to the stack anyway588 // to avoid a push/pop misalignment.589 pushRenderLanes(workInProgress, nextBaseLanes);590 return null;591 } else {592 // Rendering at offscreen, so we can clear the base lanes.593 const nextState: OffscreenState = {594 baseLanes: NoLanes,595 };596 workInProgress.memoizedState = nextState;597 // Push the lanes that were skipped when we bailed out.598 const subtreeRenderLanes =599 prevState !== null ? prevState.baseLanes : renderLanes;600 pushRenderLanes(workInProgress, subtreeRenderLanes);601 }602 } else {603 let subtreeRenderLanes;604 if (prevState !== null) {605 subtreeRenderLanes = mergeLanes(prevState.baseLanes, renderLanes);606 // Since we're not hidden anymore, reset the state607 workInProgress.memoizedState = null;608 } else {609 // We weren't previously hidden, and we still aren't, so there's nothing610 // special to do. Need to push to the stack regardless, though, to avoid611 // a push/pop misalignment.612 subtreeRenderLanes = renderLanes;613 }614 pushRenderLanes(workInProgress, subtreeRenderLanes);615 }616 reconcileChildren(current, workInProgress, nextChildren, renderLanes);617 return workInProgress.child;618}619// Note: These happen to have identical begin phases, for now. We shouldn't hold620// ourselves to this constraint, though. If the behavior diverges, we should621// fork the function.622const updateLegacyHiddenComponent = updateOffscreenComponent;623function updateFragment(624 current: Fiber | null,625 workInProgress: Fiber,626 renderLanes: Lanes,627) {628 const nextChildren = workInProgress.pendingProps;629 reconcileChildren(current, workInProgress, nextChildren, renderLanes);630 return workInProgress.child;631}632function updateMode(633 current: Fiber | null,634 workInProgress: Fiber,635 renderLanes: Lanes,636) {637 const nextChildren = workInProgress.pendingProps.children;638 reconcileChildren(current, workInProgress, nextChildren, renderLanes);639 return workInProgress.child;640}641function updateProfiler(642 current: Fiber | null,643 workInProgress: Fiber,644 renderLanes: Lanes,645) {646 if (enableProfilerTimer) {647 // Reset effect durations for the next eventual effect phase.648 // These are reset during render to allow the DevTools commit hook a chance to read them,649 const stateNode = workInProgress.stateNode;650 stateNode.effectDuration = 0;651 stateNode.passiveEffectDuration = 0;652 }653 const nextProps = workInProgress.pendingProps;654 const nextChildren = nextProps.children;655 reconcileChildren(current, workInProgress, nextChildren, renderLanes);656 return workInProgress.child;657}658function markRef(current: Fiber | null, workInProgress: Fiber) {659 const ref = workInProgress.ref;660 if (661 (current === null && ref !== null) ||662 (current !== null && current.ref !== ref)663 ) {664 // Schedule a Ref effect665 workInProgress.flags |= Ref;666 }667}668function updateFunctionComponent(669 current,670 workInProgress,671 Component,672 nextProps: any,673 renderLanes,674) {675 if (__DEV__) {676 if (workInProgress.type !== workInProgress.elementType) {677 // Lazy component props can't be validated in createElement678 // because they're only guaranteed to be resolved here.679 const innerPropTypes = Component.propTypes;680 if (innerPropTypes) {681 checkPropTypes(682 innerPropTypes,683 nextProps, // Resolved props684 'prop',685 getComponentName(Component),686 );687 }688 }689 }690 let context;691 if (!disableLegacyContext) {692 const unmaskedContext = getUnmaskedContext(workInProgress, Component, true);693 context = getMaskedContext(workInProgress, unmaskedContext);694 }695 let nextChildren;696 prepareToReadContext(workInProgress, renderLanes);697 if (__DEV__) {698 ReactCurrentOwner.current = workInProgress;699 setIsRendering(true);700 nextChildren = renderWithHooks(701 current,702 workInProgress,703 Component,704 nextProps,705 context,706 renderLanes,707 );708 if (709 debugRenderPhaseSideEffectsForStrictMode &&710 workInProgress.mode & StrictMode711 ) {712 disableLogs();713 try {714 nextChildren = renderWithHooks(715 current,716 workInProgress,717 Component,718 nextProps,719 context,720 renderLanes,721 );722 } finally {723 reenableLogs();724 }725 }726 setIsRendering(false);727 } else {728 nextChildren = renderWithHooks(729 current,730 workInProgress,731 Component,732 nextProps,733 context,734 renderLanes,735 );736 }737 if (current !== null && !didReceiveUpdate) {738 bailoutHooks(current, workInProgress, renderLanes);739 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);740 }741 // React DevTools reads this flag.742 workInProgress.flags |= PerformedWork;743 reconcileChildren(current, workInProgress, nextChildren, renderLanes);744 return workInProgress.child;745}746function updateBlock<Props, Data>(747 current: Fiber | null,748 workInProgress: Fiber,749 block: BlockComponent<Props, Data>,750 nextProps: any,751 renderLanes: Lanes,752) {753 // TODO: current can be non-null here even if the component754 // hasn't yet mounted. This happens after the first render suspends.755 // We'll need to figure out if this is fine or can cause issues.756 const render = block._render;757 const data = block._data;758 // The rest is a fork of updateFunctionComponent759 let nextChildren;760 prepareToReadContext(workInProgress, renderLanes);761 if (__DEV__) {762 ReactCurrentOwner.current = workInProgress;763 setIsRendering(true);764 nextChildren = renderWithHooks(765 current,766 workInProgress,767 render,768 nextProps,769 data,770 renderLanes,771 );772 if (773 debugRenderPhaseSideEffectsForStrictMode &&774 workInProgress.mode & StrictMode775 ) {776 disableLogs();777 try {778 nextChildren = renderWithHooks(779 current,780 workInProgress,781 render,782 nextProps,783 data,784 renderLanes,785 );786 } finally {787 reenableLogs();788 }789 }790 setIsRendering(false);791 } else {792 nextChildren = renderWithHooks(793 current,794 workInProgress,795 render,796 nextProps,797 data,798 renderLanes,799 );800 }801 if (current !== null && !didReceiveUpdate) {802 bailoutHooks(current, workInProgress, renderLanes);803 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);804 }805 // React DevTools reads this flag.806 workInProgress.flags |= PerformedWork;807 reconcileChildren(current, workInProgress, nextChildren, renderLanes);808 return workInProgress.child;809}810function updateClassComponent(811 current: Fiber | null,812 workInProgress: Fiber,813 Component: any,814 nextProps: any,815 renderLanes: Lanes,816) {817 if (__DEV__) {818 if (workInProgress.type !== workInProgress.elementType) {819 // Lazy component props can't be validated in createElement820 // because they're only guaranteed to be resolved here.821 const innerPropTypes = Component.propTypes;822 if (innerPropTypes) {823 checkPropTypes(824 innerPropTypes,825 nextProps, // Resolved props826 'prop',827 getComponentName(Component),828 );829 }830 }831 }832 // Push context providers early to prevent context stack mismatches.833 // During mounting we don't know the child context yet as the instance doesn't exist.834 // We will invalidate the child context in finishClassComponent() right after rendering.835 let hasContext;836 if (isLegacyContextProvider(Component)) {837 hasContext = true;838 pushLegacyContextProvider(workInProgress);839 } else {840 hasContext = false;841 }842 prepareToReadContext(workInProgress, renderLanes);843 const instance = workInProgress.stateNode;844 let shouldUpdate;845 if (instance === null) {846 if (current !== null) {847 // A class component without an instance only mounts if it suspended848 // inside a non-concurrent tree, in an inconsistent state. We want to849 // treat it like a new mount, even though an empty version of it already850 // committed. Disconnect the alternate pointers.851 current.alternate = null;852 workInProgress.alternate = null;853 // Since this is conceptually a new fiber, schedule a Placement effect854 workInProgress.flags |= Placement;855 }856 // In the initial pass we might need to construct the instance.857 constructClassInstance(workInProgress, Component, nextProps);858 mountClassInstance(workInProgress, Component, nextProps, renderLanes);859 shouldUpdate = true;860 } else if (current === null) {861 // In a resume, we'll already have an instance we can reuse.862 shouldUpdate = resumeMountClassInstance(863 workInProgress,864 Component,865 nextProps,866 renderLanes,867 );868 } else {869 shouldUpdate = updateClassInstance(870 current,871 workInProgress,872 Component,873 nextProps,874 renderLanes,875 );876 }877 const nextUnitOfWork = finishClassComponent(878 current,879 workInProgress,880 Component,881 shouldUpdate,882 hasContext,883 renderLanes,884 );885 if (__DEV__) {886 const inst = workInProgress.stateNode;887 if (shouldUpdate && inst.props !== nextProps) {888 if (!didWarnAboutReassigningProps) {889 console.error(890 'It looks like %s is reassigning its own `this.props` while rendering. ' +891 'This is not supported and can lead to confusing bugs.',892 getComponentName(workInProgress.type) || 'a component',893 );894 }895 didWarnAboutReassigningProps = true;896 }897 }898 return nextUnitOfWork;899}900function finishClassComponent(901 current: Fiber | null,902 workInProgress: Fiber,903 Component: any,904 shouldUpdate: boolean,905 hasContext: boolean,906 renderLanes: Lanes,907) {908 // Refs should update even if shouldComponentUpdate returns false909 markRef(current, workInProgress);910 const didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags;911 if (!shouldUpdate && !didCaptureError) {912 // Context providers should defer to sCU for rendering913 if (hasContext) {914 invalidateContextProvider(workInProgress, Component, false);915 }916 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);917 }918 const instance = workInProgress.stateNode;919 // Rerender920 ReactCurrentOwner.current = workInProgress;921 let nextChildren;922 if (923 didCaptureError &&924 typeof Component.getDerivedStateFromError !== 'function'925 ) {926 // If we captured an error, but getDerivedStateFromError is not defined,927 // unmount all the children. componentDidCatch will schedule an update to928 // re-render a fallback. This is temporary until we migrate everyone to929 // the new API.930 // TODO: Warn in a future release.931 nextChildren = null;932 if (enableProfilerTimer) {933 stopProfilerTimerIfRunning(workInProgress);934 }935 } else {936 if (__DEV__) {937 setIsRendering(true);938 nextChildren = instance.render();939 if (940 debugRenderPhaseSideEffectsForStrictMode &&941 workInProgress.mode & StrictMode942 ) {943 disableLogs();944 try {945 instance.render();946 } finally {947 reenableLogs();948 }949 }950 setIsRendering(false);951 } else {952 nextChildren = instance.render();953 }954 }955 // React DevTools reads this flag.956 workInProgress.flags |= PerformedWork;957 if (current !== null && didCaptureError) {958 // If we're recovering from an error, reconcile without reusing any of959 // the existing children. Conceptually, the normal children and the children960 // that are shown on error are two different sets, so we shouldn't reuse961 // normal children even if their identities match.962 forceUnmountCurrentAndReconcile(963 current,964 workInProgress,965 nextChildren,966 renderLanes,967 );968 } else {969 reconcileChildren(current, workInProgress, nextChildren, renderLanes);970 }971 // Memoize state using the values we just used to render.972 // TODO: Restructure so we never read values from the instance.973 workInProgress.memoizedState = instance.state;974 // The context might have changed so we need to recalculate it.975 if (hasContext) {976 invalidateContextProvider(workInProgress, Component, true);977 }978 return workInProgress.child;979}980function pushHostRootContext(workInProgress) {981 const root = (workInProgress.stateNode: FiberRoot);982 if (root.pendingContext) {983 pushTopLevelContextObject(984 workInProgress,985 root.pendingContext,986 root.pendingContext !== root.context,987 );988 } else if (root.context) {989 // Should always be set990 pushTopLevelContextObject(workInProgress, root.context, false);991 }992 pushHostContainer(workInProgress, root.containerInfo);993}994function updateHostRoot(current, workInProgress, renderLanes) {995 pushHostRootContext(workInProgress);996 const updateQueue = workInProgress.updateQueue;997 invariant(998 current !== null && updateQueue !== null,999 'If the root does not have an updateQueue, we should have already ' +1000 'bailed out. This error is likely caused by a bug in React. Please ' +1001 'file an issue.',1002 );1003 const nextProps = workInProgress.pendingProps;1004 const prevState = workInProgress.memoizedState;1005 const prevChildren = prevState !== null ? prevState.element : null;1006 cloneUpdateQueue(current, workInProgress);1007 processUpdateQueue(workInProgress, nextProps, null, renderLanes);1008 const nextState = workInProgress.memoizedState;1009 // Caution: React DevTools currently depends on this property1010 // being called "element".1011 const nextChildren = nextState.element;1012 if (nextChildren === prevChildren) {1013 resetHydrationState();1014 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1015 }1016 const root: FiberRoot = workInProgress.stateNode;1017 if (root.hydrate && enterHydrationState(workInProgress)) {1018 // If we don't have any current children this might be the first pass.1019 // We always try to hydrate. If this isn't a hydration pass there won't1020 // be any children to hydrate which is effectively the same thing as1021 // not hydrating.1022 if (supportsHydration) {1023 const mutableSourceEagerHydrationData =1024 root.mutableSourceEagerHydrationData;1025 if (mutableSourceEagerHydrationData != null) {1026 for (let i = 0; i < mutableSourceEagerHydrationData.length; i += 2) {1027 const mutableSource = ((mutableSourceEagerHydrationData[1028 i1029 ]: any): MutableSource<any>);1030 const version = mutableSourceEagerHydrationData[i + 1];1031 setWorkInProgressVersion(mutableSource, version);1032 }1033 }1034 }1035 const child = mountChildFibers(1036 workInProgress,1037 null,1038 nextChildren,1039 renderLanes,1040 );1041 workInProgress.child = child;1042 let node = child;1043 while (node) {1044 // Mark each child as hydrating. This is a fast path to know whether this1045 // tree is part of a hydrating tree. This is used to determine if a child1046 // node has fully mounted yet, and for scheduling event replaying.1047 // Conceptually this is similar to Placement in that a new subtree is1048 // inserted into the React tree here. It just happens to not need DOM1049 // mutations because it already exists.1050 node.flags = (node.flags & ~Placement) | Hydrating;1051 node = node.sibling;1052 }1053 } else {1054 // Otherwise reset hydration state in case we aborted and resumed another1055 // root.1056 reconcileChildren(current, workInProgress, nextChildren, renderLanes);1057 resetHydrationState();1058 }1059 return workInProgress.child;1060}1061function updateHostComponent(1062 current: Fiber | null,1063 workInProgress: Fiber,1064 renderLanes: Lanes,1065) {1066 pushHostContext(workInProgress);1067 if (current === null) {1068 tryToClaimNextHydratableInstance(workInProgress);1069 }1070 const type = workInProgress.type;1071 const nextProps = workInProgress.pendingProps;1072 const prevProps = current !== null ? current.memoizedProps : null;1073 let nextChildren = nextProps.children;1074 const isDirectTextChild = shouldSetTextContent(type, nextProps);1075 if (isDirectTextChild) {1076 // We special case a direct text child of a host node. This is a common1077 // case. We won't handle it as a reified child. We will instead handle1078 // this in the host environment that also has access to this prop. That1079 // avoids allocating another HostText fiber and traversing it.1080 nextChildren = null;1081 } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {1082 // If we're switching from a direct text child to a normal child, or to1083 // empty, we need to schedule the text content to be reset.1084 workInProgress.flags |= ContentReset;1085 }1086 // React DevTools reads this flag.1087 workInProgress.flags |= PerformedWork;1088 markRef(current, workInProgress);1089 reconcileChildren(current, workInProgress, nextChildren, renderLanes);1090 return workInProgress.child;1091}1092function updateHostText(current, workInProgress) {1093 if (current === null) {1094 tryToClaimNextHydratableInstance(workInProgress);1095 }1096 // Nothing to do here. This is terminal. We'll do the completion step1097 // immediately after.1098 return null;1099}1100function mountLazyComponent(1101 _current,1102 workInProgress,1103 elementType,1104 updateLanes,1105 renderLanes,1106) {1107 if (_current !== null) {1108 // A lazy component only mounts if it suspended inside a non-1109 // concurrent tree, in an inconsistent state. We want to treat it like1110 // a new mount, even though an empty version of it already committed.1111 // Disconnect the alternate pointers.1112 _current.alternate = null;1113 workInProgress.alternate = null;1114 // Since this is conceptually a new fiber, schedule a Placement effect1115 workInProgress.flags |= Placement;1116 }1117 const props = workInProgress.pendingProps;1118 const lazyComponent: LazyComponentType<any, any> = elementType;1119 const payload = lazyComponent._payload;1120 const init = lazyComponent._init;1121 let Component = init(payload);1122 // Store the unwrapped component in the type.1123 workInProgress.type = Component;1124 const resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component));1125 const resolvedProps = resolveDefaultProps(Component, props);1126 let child;1127 switch (resolvedTag) {1128 case FunctionComponent: {1129 if (__DEV__) {1130 validateFunctionComponentInDev(workInProgress, Component);1131 workInProgress.type = Component = resolveFunctionForHotReloading(1132 Component,1133 );1134 }1135 child = updateFunctionComponent(1136 null,1137 workInProgress,1138 Component,1139 resolvedProps,1140 renderLanes,1141 );1142 return child;1143 }1144 case ClassComponent: {1145 if (__DEV__) {1146 workInProgress.type = Component = resolveClassForHotReloading(1147 Component,1148 );1149 }1150 child = updateClassComponent(1151 null,1152 workInProgress,1153 Component,1154 resolvedProps,1155 renderLanes,1156 );1157 return child;1158 }1159 case ForwardRef: {1160 if (__DEV__) {1161 workInProgress.type = Component = resolveForwardRefForHotReloading(1162 Component,1163 );1164 }1165 child = updateForwardRef(1166 null,1167 workInProgress,1168 Component,1169 resolvedProps,1170 renderLanes,1171 );1172 return child;1173 }1174 case MemoComponent: {1175 if (__DEV__) {1176 if (workInProgress.type !== workInProgress.elementType) {1177 const outerPropTypes = Component.propTypes;1178 if (outerPropTypes) {1179 checkPropTypes(1180 outerPropTypes,1181 resolvedProps, // Resolved for outer only1182 'prop',1183 getComponentName(Component),1184 );1185 }1186 }1187 }1188 child = updateMemoComponent(1189 null,1190 workInProgress,1191 Component,1192 resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too1193 updateLanes,1194 renderLanes,1195 );1196 return child;1197 }1198 case Block: {1199 if (enableBlocksAPI) {1200 // TODO: Resolve for Hot Reloading.1201 child = updateBlock(1202 null,1203 workInProgress,1204 Component,1205 props,1206 renderLanes,1207 );1208 return child;1209 }1210 break;1211 }1212 }1213 let hint = '';1214 if (__DEV__) {1215 if (1216 Component !== null &&1217 typeof Component === 'object' &&1218 Component.$$typeof === REACT_LAZY_TYPE1219 ) {1220 hint = ' Did you wrap a component in React.lazy() more than once?';1221 }1222 }1223 // This message intentionally doesn't mention ForwardRef or MemoComponent1224 // because the fact that it's a separate type of work is an1225 // implementation detail.1226 invariant(1227 false,1228 'Element type is invalid. Received a promise that resolves to: %s. ' +1229 'Lazy element type must resolve to a class or function.%s',1230 Component,1231 hint,1232 );1233}1234function mountIncompleteClassComponent(1235 _current,1236 workInProgress,1237 Component,1238 nextProps,1239 renderLanes,1240) {1241 if (_current !== null) {1242 // An incomplete component only mounts if it suspended inside a non-1243 // concurrent tree, in an inconsistent state. We want to treat it like1244 // a new mount, even though an empty version of it already committed.1245 // Disconnect the alternate pointers.1246 _current.alternate = null;1247 workInProgress.alternate = null;1248 // Since this is conceptually a new fiber, schedule a Placement effect1249 workInProgress.flags |= Placement;1250 }1251 // Promote the fiber to a class and try rendering again.1252 workInProgress.tag = ClassComponent;1253 // The rest of this function is a fork of `updateClassComponent`1254 // Push context providers early to prevent context stack mismatches.1255 // During mounting we don't know the child context yet as the instance doesn't exist.1256 // We will invalidate the child context in finishClassComponent() right after rendering.1257 let hasContext;1258 if (isLegacyContextProvider(Component)) {1259 hasContext = true;1260 pushLegacyContextProvider(workInProgress);1261 } else {1262 hasContext = false;1263 }1264 prepareToReadContext(workInProgress, renderLanes);1265 constructClassInstance(workInProgress, Component, nextProps);1266 mountClassInstance(workInProgress, Component, nextProps, renderLanes);1267 return finishClassComponent(1268 null,1269 workInProgress,1270 Component,1271 true,1272 hasContext,1273 renderLanes,1274 );1275}1276function mountIndeterminateComponent(1277 _current,1278 workInProgress,1279 Component,1280 renderLanes,1281) {1282 if (_current !== null) {1283 // An indeterminate component only mounts if it suspended inside a non-1284 // concurrent tree, in an inconsistent state. We want to treat it like1285 // a new mount, even though an empty version of it already committed.1286 // Disconnect the alternate pointers.1287 _current.alternate = null;1288 workInProgress.alternate = null;1289 // Since this is conceptually a new fiber, schedule a Placement effect1290 workInProgress.flags |= Placement;1291 }1292 const props = workInProgress.pendingProps;1293 let context;1294 if (!disableLegacyContext) {1295 const unmaskedContext = getUnmaskedContext(1296 workInProgress,1297 Component,1298 false,1299 );1300 context = getMaskedContext(workInProgress, unmaskedContext);1301 }1302 prepareToReadContext(workInProgress, renderLanes);1303 let value;1304 if (__DEV__) {1305 if (1306 Component.prototype &&1307 typeof Component.prototype.render === 'function'1308 ) {1309 const componentName = getComponentName(Component) || 'Unknown';1310 if (!didWarnAboutBadClass[componentName]) {1311 console.error(1312 "The <%s /> component appears to have a render method, but doesn't extend React.Component. " +1313 'This is likely to cause errors. Change %s to extend React.Component instead.',1314 componentName,1315 componentName,1316 );1317 didWarnAboutBadClass[componentName] = true;1318 }1319 }1320 if (workInProgress.mode & StrictMode) {1321 ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);1322 }1323 setIsRendering(true);1324 ReactCurrentOwner.current = workInProgress;1325 value = renderWithHooks(1326 null,1327 workInProgress,1328 Component,1329 props,1330 context,1331 renderLanes,1332 );1333 setIsRendering(false);1334 } else {1335 value = renderWithHooks(1336 null,1337 workInProgress,1338 Component,1339 props,1340 context,1341 renderLanes,1342 );1343 }1344 // React DevTools reads this flag.1345 workInProgress.flags |= PerformedWork;1346 if (__DEV__) {1347 // Support for module components is deprecated and is removed behind a flag.1348 // Whether or not it would crash later, we want to show a good message in DEV first.1349 if (1350 typeof value === 'object' &&1351 value !== null &&1352 typeof value.render === 'function' &&1353 value.$$typeof === undefined1354 ) {1355 const componentName = getComponentName(Component) || 'Unknown';1356 if (!didWarnAboutModulePatternComponent[componentName]) {1357 console.error(1358 'The <%s /> component appears to be a function component that returns a class instance. ' +1359 'Change %s to a class that extends React.Component instead. ' +1360 "If you can't use a class try assigning the prototype on the function as a workaround. " +1361 "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " +1362 'cannot be called with `new` by React.',1363 componentName,1364 componentName,1365 componentName,1366 );1367 didWarnAboutModulePatternComponent[componentName] = true;1368 }1369 }1370 }1371 if (1372 // Run these checks in production only if the flag is off.1373 // Eventually we'll delete this branch altogether.1374 !disableModulePatternComponents &&1375 typeof value === 'object' &&1376 value !== null &&1377 typeof value.render === 'function' &&1378 value.$$typeof === undefined1379 ) {1380 if (__DEV__) {1381 const componentName = getComponentName(Component) || 'Unknown';1382 if (!didWarnAboutModulePatternComponent[componentName]) {1383 console.error(1384 'The <%s /> component appears to be a function component that returns a class instance. ' +1385 'Change %s to a class that extends React.Component instead. ' +1386 "If you can't use a class try assigning the prototype on the function as a workaround. " +1387 "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " +1388 'cannot be called with `new` by React.',1389 componentName,1390 componentName,1391 componentName,1392 );1393 didWarnAboutModulePatternComponent[componentName] = true;1394 }1395 }1396 // Proceed under the assumption that this is a class instance1397 workInProgress.tag = ClassComponent;1398 // Throw out any hooks that were used.1399 workInProgress.memoizedState = null;1400 workInProgress.updateQueue = null;1401 // Push context providers early to prevent context stack mismatches.1402 // During mounting we don't know the child context yet as the instance doesn't exist.1403 // We will invalidate the child context in finishClassComponent() right after rendering.1404 let hasContext = false;1405 if (isLegacyContextProvider(Component)) {1406 hasContext = true;1407 pushLegacyContextProvider(workInProgress);1408 } else {1409 hasContext = false;1410 }1411 workInProgress.memoizedState =1412 value.state !== null && value.state !== undefined ? value.state : null;1413 initializeUpdateQueue(workInProgress);1414 const getDerivedStateFromProps = Component.getDerivedStateFromProps;1415 if (typeof getDerivedStateFromProps === 'function') {1416 applyDerivedStateFromProps(1417 workInProgress,1418 Component,1419 getDerivedStateFromProps,1420 props,1421 );1422 }1423 adoptClassInstance(workInProgress, value);1424 mountClassInstance(workInProgress, Component, props, renderLanes);1425 return finishClassComponent(1426 null,1427 workInProgress,1428 Component,1429 true,1430 hasContext,1431 renderLanes,1432 );1433 } else {1434 // Proceed under the assumption that this is a function component1435 workInProgress.tag = FunctionComponent;1436 if (__DEV__) {1437 if (disableLegacyContext && Component.contextTypes) {1438 console.error(1439 '%s uses the legacy contextTypes API which is no longer supported. ' +1440 'Use React.createContext() with React.useContext() instead.',1441 getComponentName(Component) || 'Unknown',1442 );1443 }1444 if (1445 debugRenderPhaseSideEffectsForStrictMode &&1446 workInProgress.mode & StrictMode1447 ) {1448 disableLogs();1449 try {1450 value = renderWithHooks(1451 null,1452 workInProgress,1453 Component,1454 props,1455 context,1456 renderLanes,1457 );1458 } finally {1459 reenableLogs();1460 }1461 }1462 }1463 reconcileChildren(null, workInProgress, value, renderLanes);1464 if (__DEV__) {1465 validateFunctionComponentInDev(workInProgress, Component);1466 }1467 return workInProgress.child;1468 }1469}1470function validateFunctionComponentInDev(workInProgress: Fiber, Component: any) {1471 if (__DEV__) {1472 if (Component) {1473 if (Component.childContextTypes) {1474 console.error(1475 '%s(...): childContextTypes cannot be defined on a function component.',1476 Component.displayName || Component.name || 'Component',1477 );1478 }1479 }1480 if (workInProgress.ref !== null) {1481 let info = '';1482 const ownerName = getCurrentFiberOwnerNameInDevOrNull();1483 if (ownerName) {1484 info += '\n\nCheck the render method of `' + ownerName + '`.';1485 }1486 let warningKey = ownerName || workInProgress._debugID || '';1487 const debugSource = workInProgress._debugSource;1488 if (debugSource) {1489 warningKey = debugSource.fileName + ':' + debugSource.lineNumber;1490 }1491 if (!didWarnAboutFunctionRefs[warningKey]) {1492 didWarnAboutFunctionRefs[warningKey] = true;1493 console.error(1494 'Function components cannot be given refs. ' +1495 'Attempts to access this ref will fail. ' +1496 'Did you mean to use React.forwardRef()?%s',1497 info,1498 );1499 }1500 }1501 if (1502 warnAboutDefaultPropsOnFunctionComponents &&1503 Component.defaultProps !== undefined1504 ) {1505 const componentName = getComponentName(Component) || 'Unknown';1506 if (!didWarnAboutDefaultPropsOnFunctionComponent[componentName]) {1507 console.error(1508 '%s: Support for defaultProps will be removed from function components ' +1509 'in a future major release. Use JavaScript default parameters instead.',1510 componentName,1511 );1512 didWarnAboutDefaultPropsOnFunctionComponent[componentName] = true;1513 }1514 }1515 if (typeof Component.getDerivedStateFromProps === 'function') {1516 const componentName = getComponentName(Component) || 'Unknown';1517 if (!didWarnAboutGetDerivedStateOnFunctionComponent[componentName]) {1518 console.error(1519 '%s: Function components do not support getDerivedStateFromProps.',1520 componentName,1521 );1522 didWarnAboutGetDerivedStateOnFunctionComponent[componentName] = true;1523 }1524 }1525 if (1526 typeof Component.contextType === 'object' &&1527 Component.contextType !== null1528 ) {1529 const componentName = getComponentName(Component) || 'Unknown';1530 if (!didWarnAboutContextTypeOnFunctionComponent[componentName]) {1531 console.error(1532 '%s: Function components do not support contextType.',1533 componentName,1534 );1535 didWarnAboutContextTypeOnFunctionComponent[componentName] = true;1536 }1537 }1538 }1539}1540const SUSPENDED_MARKER: SuspenseState = {1541 dehydrated: null,1542 retryLane: NoLane,1543};1544function mountSuspenseOffscreenState(renderLanes: Lanes): OffscreenState {1545 return {1546 baseLanes: renderLanes,1547 };1548}1549function updateSuspenseOffscreenState(1550 prevOffscreenState: OffscreenState,1551 renderLanes: Lanes,1552): OffscreenState {1553 return {1554 baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes),1555 };1556}1557// TODO: Probably should inline this back1558function shouldRemainOnFallback(1559 suspenseContext: SuspenseContext,1560 current: null | Fiber,1561 workInProgress: Fiber,1562 renderLanes: Lanes,1563) {1564 // If we're already showing a fallback, there are cases where we need to1565 // remain on that fallback regardless of whether the content has resolved.1566 // For example, SuspenseList coordinates when nested content appears.1567 if (current !== null) {1568 const suspenseState: SuspenseState = current.memoizedState;1569 if (suspenseState === null) {1570 // Currently showing content. Don't hide it, even if ForceSuspenseFallack1571 // is true. More precise name might be "ForceRemainSuspenseFallback".1572 // Note: This is a factoring smell. Can't remain on a fallback if there's1573 // no fallback to remain on.1574 return false;1575 }1576 }1577 // Not currently showing content. Consult the Suspense context.1578 return hasSuspenseContext(1579 suspenseContext,1580 (ForceSuspenseFallback: SuspenseContext),1581 );1582}1583function getRemainingWorkInPrimaryTree(current: Fiber, renderLanes) {1584 // TODO: Should not remove render lanes that were pinged during this render1585 return removeLanes(current.childLanes, renderLanes);1586}1587function updateSuspenseComponent(current, workInProgress, renderLanes) {1588 const nextProps = workInProgress.pendingProps;1589 // This is used by DevTools to force a boundary to suspend.1590 if (__DEV__) {1591 if (shouldSuspend(workInProgress)) {1592 workInProgress.flags |= DidCapture;1593 }1594 }1595 let suspenseContext: SuspenseContext = suspenseStackCursor.current;1596 let showFallback = false;1597 const didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;1598 if (1599 didSuspend ||1600 shouldRemainOnFallback(1601 suspenseContext,1602 current,1603 workInProgress,1604 renderLanes,1605 )1606 ) {1607 // Something in this boundary's subtree already suspended. Switch to1608 // rendering the fallback children.1609 showFallback = true;1610 workInProgress.flags &= ~DidCapture;1611 } else {1612 // Attempting the main content1613 if (1614 current === null ||1615 (current.memoizedState: null | SuspenseState) !== null1616 ) {1617 // This is a new mount or this boundary is already showing a fallback state.1618 // Mark this subtree context as having at least one invisible parent that could1619 // handle the fallback state.1620 // Boundaries without fallbacks or should be avoided are not considered since1621 // they cannot handle preferred fallback states.1622 if (1623 nextProps.fallback !== undefined &&1624 nextProps.unstable_avoidThisFallback !== true1625 ) {1626 suspenseContext = addSubtreeSuspenseContext(1627 suspenseContext,1628 InvisibleParentSuspenseContext,1629 );1630 }1631 }1632 }1633 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);1634 pushSuspenseContext(workInProgress, suspenseContext);1635 // OK, the next part is confusing. We're about to reconcile the Suspense1636 // boundary's children. This involves some custom reconcilation logic. Two1637 // main reasons this is so complicated.1638 //1639 // First, Legacy Mode has different semantics for backwards compatibility. The1640 // primary tree will commit in an inconsistent state, so when we do the1641 // second pass to render the fallback, we do some exceedingly, uh, clever1642 // hacks to make that not totally break. Like transferring effects and1643 // deletions from hidden tree. In Concurrent Mode, it's much simpler,1644 // because we bailout on the primary tree completely and leave it in its old1645 // state, no effects. Same as what we do for Offscreen (except that1646 // Offscreen doesn't have the first render pass).1647 //1648 // Second is hydration. During hydration, the Suspense fiber has a slightly1649 // different layout, where the child points to a dehydrated fragment, which1650 // contains the DOM rendered by the server.1651 //1652 // Third, even if you set all that aside, Suspense is like error boundaries in1653 // that we first we try to render one tree, and if that fails, we render again1654 // and switch to a different tree. Like a try/catch block. So we have to track1655 // which branch we're currently rendering. Ideally we would model this using1656 // a stack.1657 if (current === null) {1658 // Initial mount1659 // If we're currently hydrating, try to hydrate this boundary.1660 // But only if this has a fallback.1661 if (nextProps.fallback !== undefined) {1662 tryToClaimNextHydratableInstance(workInProgress);1663 // This could've been a dehydrated suspense component.1664 if (enableSuspenseServerRenderer) {1665 const suspenseState: null | SuspenseState =1666 workInProgress.memoizedState;1667 if (suspenseState !== null) {1668 const dehydrated = suspenseState.dehydrated;1669 if (dehydrated !== null) {1670 return mountDehydratedSuspenseComponent(1671 workInProgress,1672 dehydrated,1673 renderLanes,1674 );1675 }1676 }1677 }1678 }1679 const nextPrimaryChildren = nextProps.children;1680 const nextFallbackChildren = nextProps.fallback;1681 if (showFallback) {1682 const fallbackFragment = mountSuspenseFallbackChildren(1683 workInProgress,1684 nextPrimaryChildren,1685 nextFallbackChildren,1686 renderLanes,1687 );1688 const primaryChildFragment: Fiber = (workInProgress.child: any);1689 primaryChildFragment.memoizedState = mountSuspenseOffscreenState(1690 renderLanes,1691 );1692 workInProgress.memoizedState = SUSPENDED_MARKER;1693 return fallbackFragment;1694 } else if (typeof nextProps.unstable_expectedLoadTime === 'number') {1695 // This is a CPU-bound tree. Skip this tree and show a placeholder to1696 // unblock the surrounding content. Then immediately retry after the1697 // initial commit.1698 const fallbackFragment = mountSuspenseFallbackChildren(1699 workInProgress,1700 nextPrimaryChildren,1701 nextFallbackChildren,1702 renderLanes,1703 );1704 const primaryChildFragment: Fiber = (workInProgress.child: any);1705 primaryChildFragment.memoizedState = mountSuspenseOffscreenState(1706 renderLanes,1707 );1708 workInProgress.memoizedState = SUSPENDED_MARKER;1709 // Since nothing actually suspended, there will nothing to ping this to1710 // get it started back up to attempt the next item. While in terms of1711 // priority this work has the same priority as this current render, it's1712 // not part of the same transition once the transition has committed. If1713 // it's sync, we still want to yield so that it can be painted.1714 // Conceptually, this is really the same as pinging. We can use any1715 // RetryLane even if it's the one currently rendering since we're leaving1716 // it behind on this node.1717 workInProgress.lanes = SomeRetryLane;1718 if (enableSchedulerTracing) {1719 markSpawnedWork(SomeRetryLane);1720 }1721 return fallbackFragment;1722 } else {1723 return mountSuspensePrimaryChildren(1724 workInProgress,1725 nextPrimaryChildren,1726 renderLanes,1727 );1728 }1729 } else {1730 // This is an update.1731 // If the current fiber has a SuspenseState, that means it's already showing1732 // a fallback.1733 const prevState: null | SuspenseState = current.memoizedState;1734 if (prevState !== null) {1735 // The current tree is already showing a fallback1736 // Special path for hydration1737 if (enableSuspenseServerRenderer) {1738 const dehydrated = prevState.dehydrated;1739 if (dehydrated !== null) {1740 if (!didSuspend) {1741 return updateDehydratedSuspenseComponent(1742 current,1743 workInProgress,1744 dehydrated,1745 prevState,1746 renderLanes,1747 );1748 } else if (1749 (workInProgress.memoizedState: null | SuspenseState) !== null1750 ) {1751 // Something suspended and we should still be in dehydrated mode.1752 // Leave the existing child in place.1753 workInProgress.child = current.child;1754 // The dehydrated completion pass expects this flag to be there1755 // but the normal suspense pass doesn't.1756 workInProgress.flags |= DidCapture;1757 return null;1758 } else {1759 // Suspended but we should no longer be in dehydrated mode.1760 // Therefore we now have to render the fallback.1761 const nextPrimaryChildren = nextProps.children;1762 const nextFallbackChildren = nextProps.fallback;1763 const fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating(1764 current,1765 workInProgress,1766 nextPrimaryChildren,1767 nextFallbackChildren,1768 renderLanes,1769 );1770 const primaryChildFragment: Fiber = (workInProgress.child: any);1771 primaryChildFragment.memoizedState = mountSuspenseOffscreenState(1772 renderLanes,1773 );1774 workInProgress.memoizedState = SUSPENDED_MARKER;1775 return fallbackChildFragment;1776 }1777 }1778 }1779 if (showFallback) {1780 const nextFallbackChildren = nextProps.fallback;1781 const nextPrimaryChildren = nextProps.children;1782 const fallbackChildFragment = updateSuspenseFallbackChildren(1783 current,1784 workInProgress,1785 nextPrimaryChildren,1786 nextFallbackChildren,1787 renderLanes,1788 );1789 const primaryChildFragment: Fiber = (workInProgress.child: any);1790 const prevOffscreenState: OffscreenState | null = (current.child: any)1791 .memoizedState;1792 primaryChildFragment.memoizedState =1793 prevOffscreenState === null1794 ? mountSuspenseOffscreenState(renderLanes)1795 : updateSuspenseOffscreenState(prevOffscreenState, renderLanes);1796 primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(1797 current,1798 renderLanes,1799 );1800 workInProgress.memoizedState = SUSPENDED_MARKER;1801 return fallbackChildFragment;1802 } else {1803 const nextPrimaryChildren = nextProps.children;1804 const primaryChildFragment = updateSuspensePrimaryChildren(1805 current,1806 workInProgress,1807 nextPrimaryChildren,1808 renderLanes,1809 );1810 workInProgress.memoizedState = null;1811 return primaryChildFragment;1812 }1813 } else {1814 // The current tree is not already showing a fallback.1815 if (showFallback) {1816 // Timed out.1817 const nextFallbackChildren = nextProps.fallback;1818 const nextPrimaryChildren = nextProps.children;1819 const fallbackChildFragment = updateSuspenseFallbackChildren(1820 current,1821 workInProgress,1822 nextPrimaryChildren,1823 nextFallbackChildren,1824 renderLanes,1825 );1826 const primaryChildFragment: Fiber = (workInProgress.child: any);1827 const prevOffscreenState: OffscreenState | null = (current.child: any)1828 .memoizedState;1829 primaryChildFragment.memoizedState =1830 prevOffscreenState === null1831 ? mountSuspenseOffscreenState(renderLanes)1832 : updateSuspenseOffscreenState(prevOffscreenState, renderLanes);1833 primaryChildFragment.childLanes = getRemainingWorkInPrimaryTree(1834 current,1835 renderLanes,1836 );1837 // Skip the primary children, and continue working on the1838 // fallback children.1839 workInProgress.memoizedState = SUSPENDED_MARKER;1840 return fallbackChildFragment;1841 } else {1842 // Still haven't timed out. Continue rendering the children, like we1843 // normally do.1844 const nextPrimaryChildren = nextProps.children;1845 const primaryChildFragment = updateSuspensePrimaryChildren(1846 current,1847 workInProgress,1848 nextPrimaryChildren,1849 renderLanes,1850 );1851 workInProgress.memoizedState = null;1852 return primaryChildFragment;1853 }1854 }1855 }1856}1857function mountSuspensePrimaryChildren(1858 workInProgress,1859 primaryChildren,1860 renderLanes,1861) {1862 const mode = workInProgress.mode;1863 const primaryChildProps: OffscreenProps = {1864 mode: 'visible',1865 children: primaryChildren,1866 };1867 const primaryChildFragment = createFiberFromOffscreen(1868 primaryChildProps,1869 mode,1870 renderLanes,1871 null,1872 );1873 primaryChildFragment.return = workInProgress;1874 workInProgress.child = primaryChildFragment;1875 return primaryChildFragment;1876}1877function mountSuspenseFallbackChildren(1878 workInProgress,1879 primaryChildren,1880 fallbackChildren,1881 renderLanes,1882) {1883 const mode = workInProgress.mode;1884 const progressedPrimaryFragment: Fiber | null = workInProgress.child;1885 const primaryChildProps: OffscreenProps = {1886 mode: 'hidden',1887 children: primaryChildren,1888 };1889 let primaryChildFragment;1890 let fallbackChildFragment;1891 if ((mode & BlockingMode) === NoMode && progressedPrimaryFragment !== null) {1892 // In legacy mode, we commit the primary tree as if it successfully1893 // completed, even though it's in an inconsistent state.1894 primaryChildFragment = progressedPrimaryFragment;1895 primaryChildFragment.childLanes = NoLanes;1896 primaryChildFragment.pendingProps = primaryChildProps;1897 if (enableProfilerTimer && workInProgress.mode & ProfileMode) {1898 // Reset the durations from the first pass so they aren't included in the1899 // final amounts. This seems counterintuitive, since we're intentionally1900 // not measuring part of the render phase, but this makes it match what we1901 // do in Concurrent Mode.1902 primaryChildFragment.actualDuration = 0;1903 primaryChildFragment.actualStartTime = -1;1904 primaryChildFragment.selfBaseDuration = 0;1905 primaryChildFragment.treeBaseDuration = 0;1906 }1907 fallbackChildFragment = createFiberFromFragment(1908 fallbackChildren,1909 mode,1910 renderLanes,1911 null,1912 );1913 } else {1914 primaryChildFragment = createFiberFromOffscreen(1915 primaryChildProps,1916 mode,1917 NoLanes,1918 null,1919 );1920 fallbackChildFragment = createFiberFromFragment(1921 fallbackChildren,1922 mode,1923 renderLanes,1924 null,1925 );1926 }1927 primaryChildFragment.return = workInProgress;1928 fallbackChildFragment.return = workInProgress;1929 primaryChildFragment.sibling = fallbackChildFragment;1930 workInProgress.child = primaryChildFragment;1931 return fallbackChildFragment;1932}1933function createWorkInProgressOffscreenFiber(1934 current: Fiber,1935 offscreenProps: OffscreenProps,1936) {1937 // The props argument to `createWorkInProgress` is `any` typed, so we use this1938 // wrapper function to constrain it.1939 return createWorkInProgress(current, offscreenProps);1940}1941function updateSuspensePrimaryChildren(1942 current,1943 workInProgress,1944 primaryChildren,1945 renderLanes,1946) {1947 const currentPrimaryChildFragment: Fiber = (current.child: any);1948 const currentFallbackChildFragment: Fiber | null =1949 currentPrimaryChildFragment.sibling;1950 const primaryChildFragment = createWorkInProgressOffscreenFiber(1951 currentPrimaryChildFragment,1952 {1953 mode: 'visible',1954 children: primaryChildren,1955 },1956 );1957 if ((workInProgress.mode & BlockingMode) === NoMode) {1958 primaryChildFragment.lanes = renderLanes;1959 }1960 primaryChildFragment.return = workInProgress;1961 primaryChildFragment.sibling = null;1962 if (currentFallbackChildFragment !== null) {1963 // Delete the fallback child fragment1964 const deletions = workInProgress.deletions;1965 if (deletions === null) {1966 workInProgress.deletions = [currentFallbackChildFragment];1967 // TODO (effects) Rename this to better reflect its new usage (e.g. ChildDeletions)1968 workInProgress.flags |= Deletion;1969 } else {1970 deletions.push(currentFallbackChildFragment);1971 }1972 }1973 workInProgress.child = primaryChildFragment;1974 return primaryChildFragment;1975}1976function updateSuspenseFallbackChildren(1977 current,1978 workInProgress,1979 primaryChildren,1980 fallbackChildren,1981 renderLanes,1982) {1983 const mode = workInProgress.mode;1984 const currentPrimaryChildFragment: Fiber = (current.child: any);1985 const currentFallbackChildFragment: Fiber | null =1986 currentPrimaryChildFragment.sibling;1987 const primaryChildProps: OffscreenProps = {1988 mode: 'hidden',1989 children: primaryChildren,1990 };1991 let primaryChildFragment;1992 if (1993 // In legacy mode, we commit the primary tree as if it successfully1994 // completed, even though it's in an inconsistent state.1995 (mode & BlockingMode) === NoMode &&1996 // Make sure we're on the second pass, i.e. the primary child fragment was1997 // already cloned. In legacy mode, the only case where this isn't true is1998 // when DevTools forces us to display a fallback; we skip the first render1999 // pass entirely and go straight to rendering the fallback. (In Concurrent2000 // Mode, SuspenseList can also trigger this scenario, but this is a legacy-2001 // only codepath.)2002 workInProgress.child !== currentPrimaryChildFragment2003 ) {2004 const progressedPrimaryFragment: Fiber = (workInProgress.child: any);2005 primaryChildFragment = progressedPrimaryFragment;2006 primaryChildFragment.childLanes = NoLanes;2007 primaryChildFragment.pendingProps = primaryChildProps;2008 if (enableProfilerTimer && workInProgress.mode & ProfileMode) {2009 // Reset the durations from the first pass so they aren't included in the2010 // final amounts. This seems counterintuitive, since we're intentionally2011 // not measuring part of the render phase, but this makes it match what we2012 // do in Concurrent Mode.2013 primaryChildFragment.actualDuration = 0;2014 primaryChildFragment.actualStartTime = -1;2015 primaryChildFragment.selfBaseDuration =2016 currentPrimaryChildFragment.selfBaseDuration;2017 primaryChildFragment.treeBaseDuration =2018 currentPrimaryChildFragment.treeBaseDuration;2019 }2020 // The fallback fiber was added as a deletion effect during the first pass.2021 // However, since we're going to remain on the fallback, we no longer want2022 // to delete it.2023 workInProgress.deletions = null;2024 } else {2025 primaryChildFragment = createWorkInProgressOffscreenFiber(2026 currentPrimaryChildFragment,2027 primaryChildProps,2028 );2029 // Since we're reusing a current tree, we need to reuse the flags, too.2030 // (We don't do this in legacy mode, because in legacy mode we don't re-use2031 // the current tree; see previous branch.)2032 primaryChildFragment.subtreeFlags =2033 currentPrimaryChildFragment.subtreeFlags & StaticMask;2034 }2035 let fallbackChildFragment;2036 if (currentFallbackChildFragment !== null) {2037 fallbackChildFragment = createWorkInProgress(2038 currentFallbackChildFragment,2039 fallbackChildren,2040 );2041 } else {2042 fallbackChildFragment = createFiberFromFragment(2043 fallbackChildren,2044 mode,2045 renderLanes,2046 null,2047 );2048 // Needs a placement effect because the parent (the Suspense boundary) already2049 // mounted but this is a new fiber.2050 fallbackChildFragment.flags |= Placement;2051 }2052 fallbackChildFragment.return = workInProgress;2053 primaryChildFragment.return = workInProgress;2054 primaryChildFragment.sibling = fallbackChildFragment;2055 workInProgress.child = primaryChildFragment;2056 return fallbackChildFragment;2057}2058function retrySuspenseComponentWithoutHydrating(2059 current: Fiber,2060 workInProgress: Fiber,2061 renderLanes: Lanes,2062) {2063 // This will add the old fiber to the deletion list2064 reconcileChildFibers(workInProgress, current.child, null, renderLanes);2065 // We're now not suspended nor dehydrated.2066 const nextProps = workInProgress.pendingProps;2067 const primaryChildren = nextProps.children;2068 const primaryChildFragment = mountSuspensePrimaryChildren(2069 workInProgress,2070 primaryChildren,2071 renderLanes,2072 );2073 // Needs a placement effect because the parent (the Suspense boundary) already2074 // mounted but this is a new fiber.2075 primaryChildFragment.flags |= Placement;2076 workInProgress.memoizedState = null;2077 return primaryChildFragment;2078}2079function mountSuspenseFallbackAfterRetryWithoutHydrating(2080 current,2081 workInProgress,2082 primaryChildren,2083 fallbackChildren,2084 renderLanes,2085) {2086 const mode = workInProgress.mode;2087 const primaryChildFragment = createFiberFromOffscreen(2088 primaryChildren,2089 mode,2090 NoLanes,2091 null,2092 );2093 const fallbackChildFragment = createFiberFromFragment(2094 fallbackChildren,2095 mode,2096 renderLanes,2097 null,2098 );2099 // Needs a placement effect because the parent (the Suspense2100 // boundary) already mounted but this is a new fiber.2101 fallbackChildFragment.flags |= Placement;2102 primaryChildFragment.return = workInProgress;2103 fallbackChildFragment.return = workInProgress;2104 primaryChildFragment.sibling = fallbackChildFragment;2105 workInProgress.child = primaryChildFragment;2106 if ((workInProgress.mode & BlockingMode) !== NoMode) {2107 // We will have dropped the effect list which contains the2108 // deletion. We need to reconcile to delete the current child.2109 reconcileChildFibers(workInProgress, current.child, null, renderLanes);2110 }2111 return fallbackChildFragment;2112}2113function mountDehydratedSuspenseComponent(2114 workInProgress: Fiber,2115 suspenseInstance: SuspenseInstance,2116 renderLanes: Lanes,2117): null | Fiber {2118 // During the first pass, we'll bail out and not drill into the children.2119 // Instead, we'll leave the content in place and try to hydrate it later.2120 if ((workInProgress.mode & BlockingMode) === NoMode) {2121 if (__DEV__) {2122 console.error(2123 'Cannot hydrate Suspense in legacy mode. Switch from ' +2124 'ReactDOM.hydrate(element, container) to ' +2125 'ReactDOM.createBlockingRoot(container, { hydrate: true })' +2126 '.render(element) or remove the Suspense components from ' +2127 'the server rendered components.',2128 );2129 }2130 workInProgress.lanes = laneToLanes(SyncLane);2131 } else if (isSuspenseInstanceFallback(suspenseInstance)) {2132 // This is a client-only boundary. Since we won't get any content from the server2133 // for this, we need to schedule that at a higher priority based on when it would2134 // have timed out. In theory we could render it in this pass but it would have the2135 // wrong priority associated with it and will prevent hydration of parent path.2136 // Instead, we'll leave work left on it to render it in a separate commit.2137 // TODO This time should be the time at which the server rendered response that is2138 // a parent to this boundary was displayed. However, since we currently don't have2139 // a protocol to transfer that time, we'll just estimate it by using the current2140 // time. This will mean that Suspense timeouts are slightly shifted to later than2141 // they should be.2142 // Schedule a normal pri update to render this content.2143 if (enableSchedulerTracing) {2144 markSpawnedWork(DefaultHydrationLane);2145 }2146 workInProgress.lanes = laneToLanes(DefaultHydrationLane);2147 } else {2148 // We'll continue hydrating the rest at offscreen priority since we'll already2149 // be showing the right content coming from the server, it is no rush.2150 workInProgress.lanes = laneToLanes(OffscreenLane);2151 if (enableSchedulerTracing) {2152 markSpawnedWork(OffscreenLane);2153 }2154 }2155 return null;2156}2157function updateDehydratedSuspenseComponent(2158 current: Fiber,2159 workInProgress: Fiber,2160 suspenseInstance: SuspenseInstance,2161 suspenseState: SuspenseState,2162 renderLanes: Lanes,2163): null | Fiber {2164 // We should never be hydrating at this point because it is the first pass,2165 // but after we've already committed once.2166 warnIfHydrating();2167 if ((getExecutionContext() & RetryAfterError) !== NoContext) {2168 return retrySuspenseComponentWithoutHydrating(2169 current,2170 workInProgress,2171 renderLanes,2172 );2173 }2174 if ((workInProgress.mode & BlockingMode) === NoMode) {2175 return retrySuspenseComponentWithoutHydrating(2176 current,2177 workInProgress,2178 renderLanes,2179 );2180 }2181 if (isSuspenseInstanceFallback(suspenseInstance)) {2182 // This boundary is in a permanent fallback state. In this case, we'll never2183 // get an update and we'll never be able to hydrate the final content. Let's just try the2184 // client side render instead.2185 return retrySuspenseComponentWithoutHydrating(2186 current,2187 workInProgress,2188 renderLanes,2189 );2190 }2191 // We use lanes to indicate that a child might depend on context, so if2192 // any context has changed, we need to treat is as if the input might have changed.2193 const hasContextChanged = includesSomeLane(renderLanes, current.childLanes);2194 if (didReceiveUpdate || hasContextChanged) {2195 // This boundary has changed since the first render. This means that we are now unable to2196 // hydrate it. We might still be able to hydrate it using a higher priority lane.2197 const root = getWorkInProgressRoot();2198 if (root !== null) {2199 const attemptHydrationAtLane = getBumpedLaneForHydration(2200 root,2201 renderLanes,2202 );2203 if (2204 attemptHydrationAtLane !== NoLane &&2205 attemptHydrationAtLane !== suspenseState.retryLane2206 ) {2207 // Intentionally mutating since this render will get interrupted. This2208 // is one of the very rare times where we mutate the current tree2209 // during the render phase.2210 suspenseState.retryLane = attemptHydrationAtLane;2211 // TODO: Ideally this would inherit the event time of the current render2212 const eventTime = NoTimestamp;2213 scheduleUpdateOnFiber(current, attemptHydrationAtLane, eventTime);2214 } else {2215 // We have already tried to ping at a higher priority than we're rendering with2216 // so if we got here, we must have failed to hydrate at those levels. We must2217 // now give up. Instead, we're going to delete the whole subtree and instead inject2218 // a new real Suspense boundary to take its place, which may render content2219 // or fallback. This might suspend for a while and if it does we might still have2220 // an opportunity to hydrate before this pass commits.2221 }2222 }2223 // If we have scheduled higher pri work above, this will probably just abort the render2224 // since we now have higher priority work, but in case it doesn't, we need to prepare to2225 // render something, if we time out. Even if that requires us to delete everything and2226 // skip hydration.2227 // Delay having to do this as long as the suspense timeout allows us.2228 renderDidSuspendDelayIfPossible();2229 return retrySuspenseComponentWithoutHydrating(2230 current,2231 workInProgress,2232 renderLanes,2233 );2234 } else if (isSuspenseInstancePending(suspenseInstance)) {2235 // This component is still pending more data from the server, so we can't hydrate its2236 // content. We treat it as if this component suspended itself. It might seem as if2237 // we could just try to render it client-side instead. However, this will perform a2238 // lot of unnecessary work and is unlikely to complete since it often will suspend2239 // on missing data anyway. Additionally, the server might be able to render more2240 // than we can on the client yet. In that case we'd end up with more fallback states2241 // on the client than if we just leave it alone. If the server times out or errors2242 // these should update this boundary to the permanent Fallback state instead.2243 // Mark it as having captured (i.e. suspended).2244 workInProgress.flags |= DidCapture;2245 // Leave the child in place. I.e. the dehydrated fragment.2246 workInProgress.child = current.child;2247 // Register a callback to retry this boundary once the server has sent the result.2248 let retry = retryDehydratedSuspenseBoundary.bind(null, current);2249 if (enableSchedulerTracing) {2250 retry = Schedule_tracing_wrap(retry);2251 }2252 registerSuspenseInstanceRetry(suspenseInstance, retry);2253 return null;2254 } else {2255 // This is the first attempt.2256 reenterHydrationStateFromDehydratedSuspenseInstance(2257 workInProgress,2258 suspenseInstance,2259 );2260 const nextProps = workInProgress.pendingProps;2261 const primaryChildren = nextProps.children;2262 const primaryChildFragment = mountSuspensePrimaryChildren(2263 workInProgress,2264 primaryChildren,2265 renderLanes,2266 );2267 // Mark the children as hydrating. This is a fast path to know whether this2268 // tree is part of a hydrating tree. This is used to determine if a child2269 // node has fully mounted yet, and for scheduling event replaying.2270 // Conceptually this is similar to Placement in that a new subtree is2271 // inserted into the React tree here. It just happens to not need DOM2272 // mutations because it already exists.2273 primaryChildFragment.flags |= Hydrating;2274 return primaryChildFragment;2275 }2276}2277function scheduleWorkOnFiber(fiber: Fiber, renderLanes: Lanes) {2278 fiber.lanes = mergeLanes(fiber.lanes, renderLanes);2279 const alternate = fiber.alternate;2280 if (alternate !== null) {2281 alternate.lanes = mergeLanes(alternate.lanes, renderLanes);2282 }2283 scheduleWorkOnParentPath(fiber.return, renderLanes);2284}2285function propagateSuspenseContextChange(2286 workInProgress: Fiber,2287 firstChild: null | Fiber,2288 renderLanes: Lanes,2289): void {2290 // Mark any Suspense boundaries with fallbacks as having work to do.2291 // If they were previously forced into fallbacks, they may now be able2292 // to unblock.2293 let node = firstChild;2294 while (node !== null) {2295 if (node.tag === SuspenseComponent) {2296 const state: SuspenseState | null = node.memoizedState;2297 if (state !== null) {2298 scheduleWorkOnFiber(node, renderLanes);2299 }2300 } else if (node.tag === SuspenseListComponent) {2301 // If the tail is hidden there might not be an Suspense boundaries2302 // to schedule work on. In this case we have to schedule it on the2303 // list itself.2304 // We don't have to traverse to the children of the list since2305 // the list will propagate the change when it rerenders.2306 scheduleWorkOnFiber(node, renderLanes);2307 } else if (node.child !== null) {2308 node.child.return = node;2309 node = node.child;2310 continue;2311 }2312 if (node === workInProgress) {2313 return;2314 }2315 while (node.sibling === null) {2316 if (node.return === null || node.return === workInProgress) {2317 return;2318 }2319 node = node.return;2320 }2321 node.sibling.return = node.return;2322 node = node.sibling;2323 }2324}2325function findLastContentRow(firstChild: null | Fiber): null | Fiber {2326 // This is going to find the last row among these children that is already2327 // showing content on the screen, as opposed to being in fallback state or2328 // new. If a row has multiple Suspense boundaries, any of them being in the2329 // fallback state, counts as the whole row being in a fallback state.2330 // Note that the "rows" will be workInProgress, but any nested children2331 // will still be current since we haven't rendered them yet. The mounted2332 // order may not be the same as the new order. We use the new order.2333 let row = firstChild;2334 let lastContentRow: null | Fiber = null;2335 while (row !== null) {2336 const currentRow = row.alternate;2337 // New rows can't be content rows.2338 if (currentRow !== null && findFirstSuspended(currentRow) === null) {2339 lastContentRow = row;2340 }2341 row = row.sibling;2342 }2343 return lastContentRow;2344}2345type SuspenseListRevealOrder = 'forwards' | 'backwards' | 'together' | void;2346function validateRevealOrder(revealOrder: SuspenseListRevealOrder) {2347 if (__DEV__) {2348 if (2349 revealOrder !== undefined &&2350 revealOrder !== 'forwards' &&2351 revealOrder !== 'backwards' &&2352 revealOrder !== 'together' &&2353 !didWarnAboutRevealOrder[revealOrder]2354 ) {2355 didWarnAboutRevealOrder[revealOrder] = true;2356 if (typeof revealOrder === 'string') {2357 switch (revealOrder.toLowerCase()) {2358 case 'together':2359 case 'forwards':2360 case 'backwards': {2361 console.error(2362 '"%s" is not a valid value for revealOrder on <SuspenseList />. ' +2363 'Use lowercase "%s" instead.',2364 revealOrder,2365 revealOrder.toLowerCase(),2366 );2367 break;2368 }2369 case 'forward':2370 case 'backward': {2371 console.error(2372 '"%s" is not a valid value for revealOrder on <SuspenseList />. ' +2373 'React uses the -s suffix in the spelling. Use "%ss" instead.',2374 revealOrder,2375 revealOrder.toLowerCase(),2376 );2377 break;2378 }2379 default:2380 console.error(2381 '"%s" is not a supported revealOrder on <SuspenseList />. ' +2382 'Did you mean "together", "forwards" or "backwards"?',2383 revealOrder,2384 );2385 break;2386 }2387 } else {2388 console.error(2389 '%s is not a supported value for revealOrder on <SuspenseList />. ' +2390 'Did you mean "together", "forwards" or "backwards"?',2391 revealOrder,2392 );2393 }2394 }2395 }2396}2397function validateTailOptions(2398 tailMode: SuspenseListTailMode,2399 revealOrder: SuspenseListRevealOrder,2400) {2401 if (__DEV__) {2402 if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) {2403 if (tailMode !== 'collapsed' && tailMode !== 'hidden') {2404 didWarnAboutTailOptions[tailMode] = true;2405 console.error(2406 '"%s" is not a supported value for tail on <SuspenseList />. ' +2407 'Did you mean "collapsed" or "hidden"?',2408 tailMode,2409 );2410 } else if (revealOrder !== 'forwards' && revealOrder !== 'backwards') {2411 didWarnAboutTailOptions[tailMode] = true;2412 console.error(2413 '<SuspenseList tail="%s" /> is only valid if revealOrder is ' +2414 '"forwards" or "backwards". ' +2415 'Did you mean to specify revealOrder="forwards"?',2416 tailMode,2417 );2418 }2419 }2420 }2421}2422function validateSuspenseListNestedChild(childSlot: mixed, index: number) {2423 if (__DEV__) {2424 const isArray = Array.isArray(childSlot);2425 const isIterable =2426 !isArray && typeof getIteratorFn(childSlot) === 'function';2427 if (isArray || isIterable) {2428 const type = isArray ? 'array' : 'iterable';2429 console.error(2430 'A nested %s was passed to row #%s in <SuspenseList />. Wrap it in ' +2431 'an additional SuspenseList to configure its revealOrder: ' +2432 '<SuspenseList revealOrder=...> ... ' +2433 '<SuspenseList revealOrder=...>{%s}</SuspenseList> ... ' +2434 '</SuspenseList>',2435 type,2436 index,2437 type,2438 );2439 return false;2440 }2441 }2442 return true;2443}2444function validateSuspenseListChildren(2445 children: mixed,2446 revealOrder: SuspenseListRevealOrder,2447) {2448 if (__DEV__) {2449 if (2450 (revealOrder === 'forwards' || revealOrder === 'backwards') &&2451 children !== undefined &&2452 children !== null &&2453 children !== false2454 ) {2455 if (Array.isArray(children)) {2456 for (let i = 0; i < children.length; i++) {2457 if (!validateSuspenseListNestedChild(children[i], i)) {2458 return;2459 }2460 }2461 } else {2462 const iteratorFn = getIteratorFn(children);2463 if (typeof iteratorFn === 'function') {2464 const childrenIterator = iteratorFn.call(children);2465 if (childrenIterator) {2466 let step = childrenIterator.next();2467 let i = 0;2468 for (; !step.done; step = childrenIterator.next()) {2469 if (!validateSuspenseListNestedChild(step.value, i)) {2470 return;2471 }2472 i++;2473 }2474 }2475 } else {2476 console.error(2477 'A single row was passed to a <SuspenseList revealOrder="%s" />. ' +2478 'This is not useful since it needs multiple rows. ' +2479 'Did you mean to pass multiple children or an array?',2480 revealOrder,2481 );2482 }2483 }2484 }2485 }2486}2487function initSuspenseListRenderState(2488 workInProgress: Fiber,2489 isBackwards: boolean,2490 tail: null | Fiber,2491 lastContentRow: null | Fiber,2492 tailMode: SuspenseListTailMode,2493): void {2494 const renderState: null | SuspenseListRenderState =2495 workInProgress.memoizedState;2496 if (renderState === null) {2497 workInProgress.memoizedState = ({2498 isBackwards: isBackwards,2499 rendering: null,2500 renderingStartTime: 0,2501 last: lastContentRow,2502 tail: tail,2503 tailMode: tailMode,2504 }: SuspenseListRenderState);2505 } else {2506 // We can reuse the existing object from previous renders.2507 renderState.isBackwards = isBackwards;2508 renderState.rendering = null;2509 renderState.renderingStartTime = 0;2510 renderState.last = lastContentRow;2511 renderState.tail = tail;2512 renderState.tailMode = tailMode;2513 }2514}2515// This can end up rendering this component multiple passes.2516// The first pass splits the children fibers into two sets. A head and tail.2517// We first render the head. If anything is in fallback state, we do another2518// pass through beginWork to rerender all children (including the tail) with2519// the force suspend context. If the first render didn't have anything in2520// in fallback state. Then we render each row in the tail one-by-one.2521// That happens in the completeWork phase without going back to beginWork.2522function updateSuspenseListComponent(2523 current: Fiber | null,2524 workInProgress: Fiber,2525 renderLanes: Lanes,2526) {2527 const nextProps = workInProgress.pendingProps;2528 const revealOrder: SuspenseListRevealOrder = nextProps.revealOrder;2529 const tailMode: SuspenseListTailMode = nextProps.tail;2530 const newChildren = nextProps.children;2531 validateRevealOrder(revealOrder);2532 validateTailOptions(tailMode, revealOrder);2533 validateSuspenseListChildren(newChildren, revealOrder);2534 reconcileChildren(current, workInProgress, newChildren, renderLanes);2535 let suspenseContext: SuspenseContext = suspenseStackCursor.current;2536 const shouldForceFallback = hasSuspenseContext(2537 suspenseContext,2538 (ForceSuspenseFallback: SuspenseContext),2539 );2540 if (shouldForceFallback) {2541 suspenseContext = setShallowSuspenseContext(2542 suspenseContext,2543 ForceSuspenseFallback,2544 );2545 workInProgress.flags |= DidCapture;2546 } else {2547 const didSuspendBefore =2548 current !== null && (current.flags & DidCapture) !== NoFlags;2549 if (didSuspendBefore) {2550 // If we previously forced a fallback, we need to schedule work2551 // on any nested boundaries to let them know to try to render2552 // again. This is the same as context updating.2553 propagateSuspenseContextChange(2554 workInProgress,2555 workInProgress.child,2556 renderLanes,2557 );2558 }2559 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);2560 }2561 pushSuspenseContext(workInProgress, suspenseContext);2562 if ((workInProgress.mode & BlockingMode) === NoMode) {2563 // In legacy mode, SuspenseList doesn't work so we just2564 // use make it a noop by treating it as the default revealOrder.2565 workInProgress.memoizedState = null;2566 } else {2567 switch (revealOrder) {2568 case 'forwards': {2569 const lastContentRow = findLastContentRow(workInProgress.child);2570 let tail;2571 if (lastContentRow === null) {2572 // The whole list is part of the tail.2573 // TODO: We could fast path by just rendering the tail now.2574 tail = workInProgress.child;2575 workInProgress.child = null;2576 } else {2577 // Disconnect the tail rows after the content row.2578 // We're going to render them separately later.2579 tail = lastContentRow.sibling;2580 lastContentRow.sibling = null;2581 }2582 initSuspenseListRenderState(2583 workInProgress,2584 false, // isBackwards2585 tail,2586 lastContentRow,2587 tailMode,2588 );2589 break;2590 }2591 case 'backwards': {2592 // We're going to find the first row that has existing content.2593 // At the same time we're going to reverse the list of everything2594 // we pass in the meantime. That's going to be our tail in reverse2595 // order.2596 let tail = null;2597 let row = workInProgress.child;2598 workInProgress.child = null;2599 while (row !== null) {2600 const currentRow = row.alternate;2601 // New rows can't be content rows.2602 if (currentRow !== null && findFirstSuspended(currentRow) === null) {2603 // This is the beginning of the main content.2604 workInProgress.child = row;2605 break;2606 }2607 const nextRow = row.sibling;2608 row.sibling = tail;2609 tail = row;2610 row = nextRow;2611 }2612 // TODO: If workInProgress.child is null, we can continue on the tail immediately.2613 initSuspenseListRenderState(2614 workInProgress,2615 true, // isBackwards2616 tail,2617 null, // last2618 tailMode,2619 );2620 break;2621 }2622 case 'together': {2623 initSuspenseListRenderState(2624 workInProgress,2625 false, // isBackwards2626 null, // tail2627 null, // last2628 undefined,2629 );2630 break;2631 }2632 default: {2633 // The default reveal order is the same as not having2634 // a boundary.2635 workInProgress.memoizedState = null;2636 }2637 }2638 }2639 return workInProgress.child;2640}2641function updatePortalComponent(2642 current: Fiber | null,2643 workInProgress: Fiber,2644 renderLanes: Lanes,2645) {2646 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);2647 const nextChildren = workInProgress.pendingProps;2648 if (current === null) {2649 // Portals are special because we don't append the children during mount2650 // but at commit. Therefore we need to track insertions which the normal2651 // flow doesn't do during mount. This doesn't happen at the root because2652 // the root always starts with a "current" with a null child.2653 // TODO: Consider unifying this with how the root works.2654 workInProgress.child = reconcileChildFibers(2655 workInProgress,2656 null,2657 nextChildren,2658 renderLanes,2659 );2660 } else {2661 reconcileChildren(current, workInProgress, nextChildren, renderLanes);2662 }2663 return workInProgress.child;2664}2665let hasWarnedAboutUsingNoValuePropOnContextProvider = false;2666function updateContextProvider(2667 current: Fiber | null,2668 workInProgress: Fiber,2669 renderLanes: Lanes,2670) {2671 const providerType: ReactProviderType<any> = workInProgress.type;2672 const context: ReactContext<any> = providerType._context;2673 const newProps = workInProgress.pendingProps;2674 const oldProps = workInProgress.memoizedProps;2675 const newValue = newProps.value;2676 if (__DEV__) {2677 if (!('value' in newProps)) {2678 if (!hasWarnedAboutUsingNoValuePropOnContextProvider) {2679 hasWarnedAboutUsingNoValuePropOnContextProvider = true;2680 console.error(2681 'The `value` prop is required for the `<Context.Provider>`. Did you misspell it or forget to pass it?',2682 );2683 }2684 }2685 const providerPropTypes = workInProgress.type.propTypes;2686 if (providerPropTypes) {2687 checkPropTypes(providerPropTypes, newProps, 'prop', 'Context.Provider');2688 }2689 }2690 pushProvider(workInProgress, newValue);2691 if (oldProps !== null) {2692 const oldValue = oldProps.value;2693 const changedBits = calculateChangedBits(context, newValue, oldValue);2694 if (changedBits === 0) {2695 // No change. Bailout early if children are the same.2696 if (2697 oldProps.children === newProps.children &&2698 !hasLegacyContextChanged()2699 ) {2700 return bailoutOnAlreadyFinishedWork(2701 current,2702 workInProgress,2703 renderLanes,2704 );2705 }2706 } else {2707 // The context value changed. Search for matching consumers and schedule2708 // them to update.2709 propagateContextChange(workInProgress, context, changedBits, renderLanes);2710 }2711 }2712 const newChildren = newProps.children;2713 reconcileChildren(current, workInProgress, newChildren, renderLanes);2714 return workInProgress.child;2715}2716let hasWarnedAboutUsingContextAsConsumer = false;2717function updateContextConsumer(2718 current: Fiber | null,2719 workInProgress: Fiber,2720 renderLanes: Lanes,2721) {2722 let context: ReactContext<any> = workInProgress.type;2723 // The logic below for Context differs depending on PROD or DEV mode. In2724 // DEV mode, we create a separate object for Context.Consumer that acts2725 // like a proxy to Context. This proxy object adds unnecessary code in PROD2726 // so we use the old behaviour (Context.Consumer references Context) to2727 // reduce size and overhead. The separate object references context via2728 // a property called "_context", which also gives us the ability to check2729 // in DEV mode if this property exists or not and warn if it does not.2730 if (__DEV__) {2731 if ((context: any)._context === undefined) {2732 // This may be because it's a Context (rather than a Consumer).2733 // Or it may be because it's older React where they're the same thing.2734 // We only want to warn if we're sure it's a new React.2735 if (context !== context.Consumer) {2736 if (!hasWarnedAboutUsingContextAsConsumer) {2737 hasWarnedAboutUsingContextAsConsumer = true;2738 console.error(2739 'Rendering <Context> directly is not supported and will be removed in ' +2740 'a future major release. Did you mean to render <Context.Consumer> instead?',2741 );2742 }2743 }2744 } else {2745 context = (context: any)._context;2746 }2747 }2748 const newProps = workInProgress.pendingProps;2749 const render = newProps.children;2750 if (__DEV__) {2751 if (typeof render !== 'function') {2752 console.error(2753 'A context consumer was rendered with multiple children, or a child ' +2754 "that isn't a function. A context consumer expects a single child " +2755 'that is a function. If you did pass a function, make sure there ' +2756 'is no trailing or leading whitespace around it.',2757 );2758 }2759 }2760 prepareToReadContext(workInProgress, renderLanes);2761 const newValue = readContext(context, newProps.unstable_observedBits);2762 let newChildren;2763 if (__DEV__) {2764 ReactCurrentOwner.current = workInProgress;2765 setIsRendering(true);2766 newChildren = render(newValue);2767 setIsRendering(false);2768 } else {2769 newChildren = render(newValue);2770 }2771 // React DevTools reads this flag.2772 workInProgress.flags |= PerformedWork;2773 reconcileChildren(current, workInProgress, newChildren, renderLanes);2774 return workInProgress.child;2775}2776function updateFundamentalComponent(current, workInProgress, renderLanes) {2777 const fundamentalImpl = workInProgress.type.impl;2778 if (fundamentalImpl.reconcileChildren === false) {2779 return null;2780 }2781 const nextProps = workInProgress.pendingProps;2782 const nextChildren = nextProps.children;2783 reconcileChildren(current, workInProgress, nextChildren, renderLanes);2784 return workInProgress.child;2785}2786function updateScopeComponent(current, workInProgress, renderLanes) {2787 const nextProps = workInProgress.pendingProps;2788 const nextChildren = nextProps.children;2789 reconcileChildren(current, workInProgress, nextChildren, renderLanes);2790 return workInProgress.child;2791}2792export function markWorkInProgressReceivedUpdate() {2793 didReceiveUpdate = true;2794}2795function bailoutOnAlreadyFinishedWork(2796 current: Fiber | null,2797 workInProgress: Fiber,2798 renderLanes: Lanes,2799): Fiber | null {2800 if (current !== null) {2801 // Reuse previous dependencies2802 workInProgress.dependencies = current.dependencies;2803 }2804 if (enableProfilerTimer) {2805 // Don't update "base" render times for bailouts.2806 stopProfilerTimerIfRunning(workInProgress);2807 }2808 markSkippedUpdateLanes(workInProgress.lanes);2809 // Check if the children have any pending work.2810 if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {2811 // The children don't have any work either. We can skip them.2812 // TODO: Once we add back resuming, we should check if the children are2813 // a work-in-progress set. If so, we need to transfer their effects.2814 return null;2815 } else {2816 // This fiber doesn't have work, but its subtree does. Clone the child2817 // fibers and continue.2818 cloneChildFibers(current, workInProgress);2819 return workInProgress.child;2820 }2821}2822function remountFiber(2823 current: Fiber,2824 oldWorkInProgress: Fiber,2825 newWorkInProgress: Fiber,2826): Fiber | null {2827 if (__DEV__) {2828 const returnFiber = oldWorkInProgress.return;2829 if (returnFiber === null) {2830 throw new Error('Cannot swap the root fiber.');2831 }2832 // Disconnect from the old current.2833 // It will get deleted.2834 current.alternate = null;2835 oldWorkInProgress.alternate = null;2836 // Connect to the new tree.2837 newWorkInProgress.index = oldWorkInProgress.index;2838 newWorkInProgress.sibling = oldWorkInProgress.sibling;2839 newWorkInProgress.return = oldWorkInProgress.return;2840 newWorkInProgress.ref = oldWorkInProgress.ref;2841 // Replace the child/sibling pointers above it.2842 if (oldWorkInProgress === returnFiber.child) {2843 returnFiber.child = newWorkInProgress;2844 } else {2845 let prevSibling = returnFiber.child;2846 if (prevSibling === null) {2847 throw new Error('Expected parent to have a child.');2848 }2849 while (prevSibling.sibling !== oldWorkInProgress) {2850 prevSibling = prevSibling.sibling;2851 if (prevSibling === null) {2852 throw new Error('Expected to find the previous sibling.');2853 }2854 }2855 prevSibling.sibling = newWorkInProgress;2856 }2857 // Delete the old fiber and place the new one.2858 // Since the old fiber is disconnected, we have to schedule it manually.2859 const deletions = returnFiber.deletions;2860 if (deletions === null) {2861 returnFiber.deletions = [current];2862 // TODO (effects) Rename this to better reflect its new usage (e.g. ChildDeletions)2863 returnFiber.flags |= Deletion;2864 } else {2865 deletions.push(current);2866 }2867 newWorkInProgress.flags |= Placement;2868 // Restart work from the new fiber.2869 return newWorkInProgress;2870 } else {2871 throw new Error(2872 'Did not expect this call in production. ' +2873 'This is a bug in React. Please file an issue.',2874 );2875 }2876}2877function beginWork(2878 current: Fiber | null,2879 workInProgress: Fiber,2880 renderLanes: Lanes,2881): Fiber | null {2882 const updateLanes = workInProgress.lanes;2883 if (__DEV__) {2884 if (workInProgress._debugNeedsRemount && current !== null) {2885 // This will restart the begin phase with a new fiber.2886 return remountFiber(2887 current,2888 workInProgress,2889 createFiberFromTypeAndProps(2890 workInProgress.type,2891 workInProgress.key,2892 workInProgress.pendingProps,2893 workInProgress._debugOwner || null,2894 workInProgress.mode,2895 workInProgress.lanes,2896 ),2897 );2898 }2899 }2900 if (current !== null) {2901 const oldProps = current.memoizedProps;2902 const newProps = workInProgress.pendingProps;2903 if (2904 oldProps !== newProps ||2905 hasLegacyContextChanged() ||2906 // Force a re-render if the implementation changed due to hot reload:2907 (__DEV__ ? workInProgress.type !== current.type : false)2908 ) {2909 // If props or context changed, mark the fiber as having performed work.2910 // This may be unset if the props are determined to be equal later (memo).2911 didReceiveUpdate = true;2912 } else if (!includesSomeLane(renderLanes, updateLanes)) {2913 didReceiveUpdate = false;2914 // This fiber does not have any pending work. Bailout without entering2915 // the begin phase. There's still some bookkeeping we that needs to be done2916 // in this optimized path, mostly pushing stuff onto the stack.2917 switch (workInProgress.tag) {2918 case HostRoot:2919 pushHostRootContext(workInProgress);2920 resetHydrationState();2921 break;2922 case HostComponent:2923 pushHostContext(workInProgress);2924 break;2925 case ClassComponent: {2926 const Component = workInProgress.type;2927 if (isLegacyContextProvider(Component)) {2928 pushLegacyContextProvider(workInProgress);2929 }2930 break;2931 }2932 case HostPortal:2933 pushHostContainer(2934 workInProgress,2935 workInProgress.stateNode.containerInfo,2936 );2937 break;2938 case ContextProvider: {2939 const newValue = workInProgress.memoizedProps.value;2940 pushProvider(workInProgress, newValue);2941 break;2942 }2943 case Profiler:2944 if (enableProfilerTimer) {2945 // Reset effect durations for the next eventual effect phase.2946 // These are reset during render to allow the DevTools commit hook a chance to read them,2947 const stateNode = workInProgress.stateNode;2948 stateNode.effectDuration = 0;2949 stateNode.passiveEffectDuration = 0;2950 }2951 break;2952 case SuspenseComponent: {2953 const state: SuspenseState | null = workInProgress.memoizedState;2954 if (state !== null) {2955 if (enableSuspenseServerRenderer) {2956 if (state.dehydrated !== null) {2957 pushSuspenseContext(2958 workInProgress,2959 setDefaultShallowSuspenseContext(suspenseStackCursor.current),2960 );2961 // We know that this component will suspend again because if it has2962 // been unsuspended it has committed as a resolved Suspense component.2963 // If it needs to be retried, it should have work scheduled on it.2964 workInProgress.flags |= DidCapture;2965 // We should never render the children of a dehydrated boundary until we2966 // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork.2967 return null;2968 }2969 }2970 // If this boundary is currently timed out, we need to decide2971 // whether to retry the primary children, or to skip over it and2972 // go straight to the fallback. Check the priority of the primary2973 // child fragment.2974 const primaryChildFragment: Fiber = (workInProgress.child: any);2975 const primaryChildLanes = primaryChildFragment.childLanes;2976 if (includesSomeLane(renderLanes, primaryChildLanes)) {2977 // The primary children have pending work. Use the normal path2978 // to attempt to render the primary children again.2979 return updateSuspenseComponent(2980 current,2981 workInProgress,2982 renderLanes,2983 );2984 } else {2985 // The primary child fragment does not have pending work marked2986 // on it2987 pushSuspenseContext(2988 workInProgress,2989 setDefaultShallowSuspenseContext(suspenseStackCursor.current),2990 );2991 // The primary children do not have pending work with sufficient2992 // priority. Bailout.2993 const child = bailoutOnAlreadyFinishedWork(2994 current,2995 workInProgress,2996 renderLanes,2997 );2998 if (child !== null) {2999 // The fallback children have pending work. Skip over the3000 // primary children and work on the fallback.3001 return child.sibling;3002 } else {3003 return null;3004 }3005 }3006 } else {3007 pushSuspenseContext(3008 workInProgress,3009 setDefaultShallowSuspenseContext(suspenseStackCursor.current),3010 );3011 }3012 break;3013 }3014 case SuspenseListComponent: {3015 const didSuspendBefore = (current.flags & DidCapture) !== NoFlags;3016 const hasChildWork = includesSomeLane(3017 renderLanes,3018 workInProgress.childLanes,3019 );3020 if (didSuspendBefore) {3021 if (hasChildWork) {3022 // If something was in fallback state last time, and we have all the3023 // same children then we're still in progressive loading state.3024 // Something might get unblocked by state updates or retries in the3025 // tree which will affect the tail. So we need to use the normal3026 // path to compute the correct tail.3027 return updateSuspenseListComponent(3028 current,3029 workInProgress,3030 renderLanes,3031 );3032 }3033 // If none of the children had any work, that means that none of3034 // them got retried so they'll still be blocked in the same way3035 // as before. We can fast bail out.3036 workInProgress.flags |= DidCapture;3037 }3038 // If nothing suspended before and we're rendering the same children,3039 // then the tail doesn't matter. Anything new that suspends will work3040 // in the "together" mode, so we can continue from the state we had.3041 const renderState = workInProgress.memoizedState;3042 if (renderState !== null) {3043 // Reset to the "together" mode in case we've started a different3044 // update in the past but didn't complete it.3045 renderState.rendering = null;3046 renderState.tail = null;3047 }3048 pushSuspenseContext(workInProgress, suspenseStackCursor.current);3049 if (hasChildWork) {3050 break;3051 } else {3052 // If none of the children had any work, that means that none of3053 // them got retried so they'll still be blocked in the same way3054 // as before. We can fast bail out.3055 return null;3056 }3057 }3058 case OffscreenComponent:3059 case LegacyHiddenComponent: {3060 // Need to check if the tree still needs to be deferred. This is3061 // almost identical to the logic used in the normal update path,3062 // so we'll just enter that. The only difference is we'll bail out3063 // at the next level instead of this one, because the child props3064 // have not changed. Which is fine.3065 // TODO: Probably should refactor `beginWork` to split the bailout3066 // path from the normal path. I'm tempted to do a labeled break here3067 // but I won't :)3068 workInProgress.lanes = NoLanes;3069 return updateOffscreenComponent(current, workInProgress, renderLanes);3070 }3071 }3072 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);3073 } else {3074 if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {3075 // This is a special case that only exists for legacy mode.3076 // See https://github.com/facebook/react/pull/19216.3077 didReceiveUpdate = true;3078 } else {3079 // An update was scheduled on this fiber, but there are no new props3080 // nor legacy context. Set this to false. If an update queue or context3081 // consumer produces a changed value, it will set this to true. Otherwise,3082 // the component will assume the children have not changed and bail out.3083 didReceiveUpdate = false;3084 }3085 }3086 } else {3087 didReceiveUpdate = false;3088 }3089 // Before entering the begin phase, clear pending update priority.3090 // TODO: This assumes that we're about to evaluate the component and process3091 // the update queue. However, there's an exception: SimpleMemoComponent3092 // sometimes bails out later in the begin phase. This indicates that we should3093 // move this assignment out of the common path and into each branch.3094 workInProgress.lanes = NoLanes;3095 switch (workInProgress.tag) {3096 case IndeterminateComponent: {3097 return mountIndeterminateComponent(3098 current,3099 workInProgress,3100 workInProgress.type,3101 renderLanes,3102 );3103 }3104 case LazyComponent: {3105 const elementType = workInProgress.elementType;3106 return mountLazyComponent(3107 current,3108 workInProgress,3109 elementType,3110 updateLanes,3111 renderLanes,3112 );3113 }3114 case FunctionComponent: {3115 const Component = workInProgress.type;3116 const unresolvedProps = workInProgress.pendingProps;3117 const resolvedProps =3118 workInProgress.elementType === Component3119 ? unresolvedProps3120 : resolveDefaultProps(Component, unresolvedProps);3121 return updateFunctionComponent(3122 current,3123 workInProgress,3124 Component,3125 resolvedProps,3126 renderLanes,3127 );3128 }3129 case ClassComponent: {3130 const Component = workInProgress.type;3131 const unresolvedProps = workInProgress.pendingProps;3132 const resolvedProps =3133 workInProgress.elementType === Component3134 ? unresolvedProps3135 : resolveDefaultProps(Component, unresolvedProps);3136 return updateClassComponent(3137 current,3138 workInProgress,3139 Component,3140 resolvedProps,3141 renderLanes,3142 );3143 }3144 case HostRoot:3145 return updateHostRoot(current, workInProgress, renderLanes);3146 case HostComponent:3147 return updateHostComponent(current, workInProgress, renderLanes);3148 case HostText:3149 return updateHostText(current, workInProgress);3150 case SuspenseComponent:3151 return updateSuspenseComponent(current, workInProgress, renderLanes);3152 case HostPortal:3153 return updatePortalComponent(current, workInProgress, renderLanes);3154 case ForwardRef: {3155 const type = workInProgress.type;3156 const unresolvedProps = workInProgress.pendingProps;3157 const resolvedProps =3158 workInProgress.elementType === type3159 ? unresolvedProps3160 : resolveDefaultProps(type, unresolvedProps);3161 return updateForwardRef(3162 current,3163 workInProgress,3164 type,3165 resolvedProps,3166 renderLanes,3167 );3168 }3169 case Fragment:3170 return updateFragment(current, workInProgress, renderLanes);3171 case Mode:3172 return updateMode(current, workInProgress, renderLanes);3173 case Profiler:3174 return updateProfiler(current, workInProgress, renderLanes);3175 case ContextProvider:3176 return updateContextProvider(current, workInProgress, renderLanes);3177 case ContextConsumer:3178 return updateContextConsumer(current, workInProgress, renderLanes);3179 case MemoComponent: {3180 const type = workInProgress.type;3181 const unresolvedProps = workInProgress.pendingProps;3182 // Resolve outer props first, then resolve inner props.3183 let resolvedProps = resolveDefaultProps(type, unresolvedProps);3184 if (__DEV__) {3185 if (workInProgress.type !== workInProgress.elementType) {3186 const outerPropTypes = type.propTypes;3187 if (outerPropTypes) {3188 checkPropTypes(3189 outerPropTypes,3190 resolvedProps, // Resolved for outer only3191 'prop',3192 getComponentName(type),3193 );3194 }3195 }3196 }3197 resolvedProps = resolveDefaultProps(type.type, resolvedProps);3198 return updateMemoComponent(3199 current,3200 workInProgress,3201 type,3202 resolvedProps,3203 updateLanes,3204 renderLanes,3205 );3206 }3207 case SimpleMemoComponent: {3208 return updateSimpleMemoComponent(3209 current,3210 workInProgress,3211 workInProgress.type,3212 workInProgress.pendingProps,3213 updateLanes,3214 renderLanes,3215 );3216 }3217 case IncompleteClassComponent: {3218 const Component = workInProgress.type;3219 const unresolvedProps = workInProgress.pendingProps;3220 const resolvedProps =3221 workInProgress.elementType === Component3222 ? unresolvedProps3223 : resolveDefaultProps(Component, unresolvedProps);3224 return mountIncompleteClassComponent(3225 current,3226 workInProgress,3227 Component,3228 resolvedProps,3229 renderLanes,3230 );3231 }3232 case SuspenseListComponent: {3233 return updateSuspenseListComponent(current, workInProgress, renderLanes);3234 }3235 case FundamentalComponent: {3236 if (enableFundamentalAPI) {3237 return updateFundamentalComponent(current, workInProgress, renderLanes);3238 }3239 break;3240 }3241 case ScopeComponent: {3242 if (enableScopeAPI) {3243 return updateScopeComponent(current, workInProgress, renderLanes);3244 }3245 break;3246 }3247 case Block: {3248 if (enableBlocksAPI) {3249 const block = workInProgress.type;3250 const props = workInProgress.pendingProps;3251 return updateBlock(current, workInProgress, block, props, renderLanes);3252 }3253 break;3254 }3255 case OffscreenComponent: {3256 return updateOffscreenComponent(current, workInProgress, renderLanes);3257 }3258 case LegacyHiddenComponent: {3259 return updateLegacyHiddenComponent(current, workInProgress, renderLanes);3260 }3261 }3262 invariant(3263 false,3264 'Unknown unit of work tag (%s). This error is likely caused by a bug in ' +3265 'React. Please file an issue.',3266 workInProgress.tag,3267 );3268}...
ReactFiberBeginWork.old.js
Source:ReactFiberBeginWork.old.js
...209 }210 }211 return updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes);212 }213 function updateOffscreenComponent(current, workInProgress, renderLanes) {214 var nextProps = workInProgress.pendingProps;215 var nextChildren = nextProps.children;216 var prevState = current !== null ? current.memoizedState : null;217 if (nextProps.mode === 'hidden' || nextProps.mode === 'unstable-defer-without-hiding') {218 if ((workInProgress.mode & ConcurrentMode) === NoMode) {219 // In legacy sync mode, don't defer the subtree. Render it now.220 // TODO: Figure out what we should do in Blocking mode.221 var nextState = {222 baseLanes: NoLanes223 };224 workInProgress.memoizedState = nextState;225 pushRenderLanes(workInProgress, renderLanes);226 } else if (!includesSomeLane(renderLanes, OffscreenLane)) {227 var nextBaseLanes;228 if (prevState !== null) {229 var prevBaseLanes = prevState.baseLanes;230 nextBaseLanes = mergeLanes(prevBaseLanes, renderLanes);231 } else {232 nextBaseLanes = renderLanes;233 } // Schedule this fiber to re-render at offscreen priority. Then bailout.234 {235 markSpawnedWork(OffscreenLane);236 }237 workInProgress.lanes = workInProgress.childLanes = laneToLanes(OffscreenLane);238 var _nextState = {239 baseLanes: nextBaseLanes240 };241 workInProgress.memoizedState = _nextState; // We're about to bail out, but we need to push this to the stack anyway242 // to avoid a push/pop misalignment.243 pushRenderLanes(workInProgress, nextBaseLanes);244 return null;245 } else {246 // Rendering at offscreen, so we can clear the base lanes.247 var _nextState2 = {248 baseLanes: NoLanes249 };250 workInProgress.memoizedState = _nextState2; // Push the lanes that were skipped when we bailed out.251 var subtreeRenderLanes = prevState !== null ? prevState.baseLanes : renderLanes;252 pushRenderLanes(workInProgress, subtreeRenderLanes);253 }254 } else {255 var _subtreeRenderLanes;256 if (prevState !== null) {257 _subtreeRenderLanes = mergeLanes(prevState.baseLanes, renderLanes); // Since we're not hidden anymore, reset the state258 workInProgress.memoizedState = null;259 } else {260 // We weren't previously hidden, and we still aren't, so there's nothing261 // special to do. Need to push to the stack regardless, though, to avoid262 // a push/pop misalignment.263 _subtreeRenderLanes = renderLanes;264 }265 pushRenderLanes(workInProgress, _subtreeRenderLanes);266 }267 reconcileChildren(current, workInProgress, nextChildren, renderLanes);268 return workInProgress.child;269 } // Note: These happen to have identical begin phases, for now. We shouldn't hold270 // ourselves to this constraint, though. If the behavior diverges, we should271 // fork the function.272 var updateLegacyHiddenComponent = updateOffscreenComponent;273 function updateFragment(current, workInProgress, renderLanes) {274 var nextChildren = workInProgress.pendingProps;275 reconcileChildren(current, workInProgress, nextChildren, renderLanes);276 return workInProgress.child;277 }278 function updateMode(current, workInProgress, renderLanes) {279 var nextChildren = workInProgress.pendingProps.children;280 reconcileChildren(current, workInProgress, nextChildren, renderLanes);281 return workInProgress.child;282 }283 function updateProfiler(current, workInProgress, renderLanes) {284 {285 workInProgress.flags |= Update; // Reset effect durations for the next eventual effect phase.286 // These are reset during render to allow the DevTools commit hook a chance to read them,287 var stateNode = workInProgress.stateNode;288 stateNode.effectDuration = 0;289 stateNode.passiveEffectDuration = 0;290 }291 var nextProps = workInProgress.pendingProps;292 var nextChildren = nextProps.children;293 reconcileChildren(current, workInProgress, nextChildren, renderLanes);294 return workInProgress.child;295 }296 function markRef(current, workInProgress) {297 var ref = workInProgress.ref;298 if (current === null && ref !== null || current !== null && current.ref !== ref) {299 // Schedule a Ref effect300 workInProgress.flags |= Ref;301 }302 }303 function updateFunctionComponent(current, workInProgress, Component, nextProps, renderLanes) {304 {305 if (workInProgress.type !== workInProgress.elementType) {306 // Lazy component props can't be validated in createElement307 // because they're only guaranteed to be resolved here.308 var innerPropTypes = Component.propTypes;309 if (innerPropTypes) {310 checkPropTypes(innerPropTypes, nextProps, // Resolved props311 'prop', getComponentName(Component));312 }313 }314 }315 var context;316 {317 var unmaskedContext = getUnmaskedContext(workInProgress, Component, true);318 context = getMaskedContext(workInProgress, unmaskedContext);319 }320 var nextChildren;321 prepareToReadContext(workInProgress, renderLanes);322 {323 ReactCurrentOwner$1.current = workInProgress;324 setIsRendering(true);325 nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderLanes);326 if ( workInProgress.mode & StrictMode) {327 disableLogs();328 try {329 nextChildren = renderWithHooks(current, workInProgress, Component, nextProps, context, renderLanes);330 } finally {331 reenableLogs();332 }333 }334 setIsRendering(false);335 }336 if (current !== null && !didReceiveUpdate) {337 bailoutHooks(current, workInProgress, renderLanes);338 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);339 } // React DevTools reads this flag.340 workInProgress.flags |= PerformedWork;341 reconcileChildren(current, workInProgress, nextChildren, renderLanes);342 return workInProgress.child;343 }344 function updateBlock(current, workInProgress, block, nextProps, renderLanes) {345 // TODO: current can be non-null here even if the component346 // hasn't yet mounted. This happens after the first render suspends.347 // We'll need to figure out if this is fine or can cause issues.348 var render = block._render;349 var data = block._data; // The rest is a fork of updateFunctionComponent350 var nextChildren;351 prepareToReadContext(workInProgress, renderLanes);352 {353 ReactCurrentOwner$1.current = workInProgress;354 setIsRendering(true);355 nextChildren = renderWithHooks(current, workInProgress, render, nextProps, data, renderLanes);356 if ( workInProgress.mode & StrictMode) {357 disableLogs();358 try {359 nextChildren = renderWithHooks(current, workInProgress, render, nextProps, data, renderLanes);360 } finally {361 reenableLogs();362 }363 }364 setIsRendering(false);365 }366 if (current !== null && !didReceiveUpdate) {367 bailoutHooks(current, workInProgress, renderLanes);368 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);369 } // React DevTools reads this flag.370 workInProgress.flags |= PerformedWork;371 reconcileChildren(current, workInProgress, nextChildren, renderLanes);372 return workInProgress.child;373 }374 function updateClassComponent(current, workInProgress, Component, nextProps, renderLanes) {375 {376 if (workInProgress.type !== workInProgress.elementType) {377 // Lazy component props can't be validated in createElement378 // because they're only guaranteed to be resolved here.379 var innerPropTypes = Component.propTypes;380 if (innerPropTypes) {381 checkPropTypes(innerPropTypes, nextProps, // Resolved props382 'prop', getComponentName(Component));383 }384 }385 } // Push context providers early to prevent context stack mismatches.386 // During mounting we don't know the child context yet as the instance doesn't exist.387 // We will invalidate the child context in finishClassComponent() right after rendering.388 var hasContext;389 if (isContextProvider(Component)) {390 hasContext = true;391 pushContextProvider(workInProgress);392 } else {393 hasContext = false;394 }395 prepareToReadContext(workInProgress, renderLanes);396 var instance = workInProgress.stateNode;397 var shouldUpdate;398 if (instance === null) {399 if (current !== null) {400 // A class component without an instance only mounts if it suspended401 // inside a non-concurrent tree, in an inconsistent state. We want to402 // treat it like a new mount, even though an empty version of it already403 // committed. Disconnect the alternate pointers.404 current.alternate = null;405 workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect406 workInProgress.flags |= Placement;407 } // In the initial pass we might need to construct the instance.408 constructClassInstance(workInProgress, Component, nextProps);409 mountClassInstance(workInProgress, Component, nextProps, renderLanes);410 shouldUpdate = true;411 } else if (current === null) {412 // In a resume, we'll already have an instance we can reuse.413 shouldUpdate = resumeMountClassInstance(workInProgress, Component, nextProps, renderLanes);414 } else {415 shouldUpdate = updateClassInstance(current, workInProgress, Component, nextProps, renderLanes);416 }417 var nextUnitOfWork = finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes);418 {419 var inst = workInProgress.stateNode;420 if (shouldUpdate && inst.props !== nextProps) {421 if (!didWarnAboutReassigningProps) {422 error('It looks like %s is reassigning its own `this.props` while rendering. ' + 'This is not supported and can lead to confusing bugs.', getComponentName(workInProgress.type) || 'a component');423 }424 didWarnAboutReassigningProps = true;425 }426 }427 return nextUnitOfWork;428 }429 function finishClassComponent(current, workInProgress, Component, shouldUpdate, hasContext, renderLanes) {430 // Refs should update even if shouldComponentUpdate returns false431 markRef(current, workInProgress);432 var didCaptureError = (workInProgress.flags & DidCapture) !== NoFlags;433 if (!shouldUpdate && !didCaptureError) {434 // Context providers should defer to sCU for rendering435 if (hasContext) {436 invalidateContextProvider(workInProgress, Component, false);437 }438 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);439 }440 var instance = workInProgress.stateNode; // Rerender441 ReactCurrentOwner$1.current = workInProgress;442 var nextChildren;443 if (didCaptureError && typeof Component.getDerivedStateFromError !== 'function') {444 // If we captured an error, but getDerivedStateFromError is not defined,445 // unmount all the children. componentDidCatch will schedule an update to446 // re-render a fallback. This is temporary until we migrate everyone to447 // the new API.448 // TODO: Warn in a future release.449 nextChildren = null;450 {451 stopProfilerTimerIfRunning();452 }453 } else {454 {455 setIsRendering(true);456 nextChildren = instance.render();457 if ( workInProgress.mode & StrictMode) {458 disableLogs();459 try {460 instance.render();461 } finally {462 reenableLogs();463 }464 }465 setIsRendering(false);466 }467 } // React DevTools reads this flag.468 workInProgress.flags |= PerformedWork;469 if (current !== null && didCaptureError) {470 // If we're recovering from an error, reconcile without reusing any of471 // the existing children. Conceptually, the normal children and the children472 // that are shown on error are two different sets, so we shouldn't reuse473 // normal children even if their identities match.474 forceUnmountCurrentAndReconcile(current, workInProgress, nextChildren, renderLanes);475 } else {476 reconcileChildren(current, workInProgress, nextChildren, renderLanes);477 } // Memoize state using the values we just used to render.478 // TODO: Restructure so we never read values from the instance.479 workInProgress.memoizedState = instance.state; // The context might have changed so we need to recalculate it.480 if (hasContext) {481 invalidateContextProvider(workInProgress, Component, true);482 }483 return workInProgress.child;484 }485 function pushHostRootContext(workInProgress) {486 var root = workInProgress.stateNode;487 if (root.pendingContext) {488 pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context);489 } else if (root.context) {490 // Should always be set491 pushTopLevelContextObject(workInProgress, root.context, false);492 }493 pushHostContainer(workInProgress, root.containerInfo);494 }495 function updateHostRoot(current, workInProgress, renderLanes) {496 pushHostRootContext(workInProgress);497 var updateQueue = workInProgress.updateQueue;498 if (!(current !== null && updateQueue !== null)) {499 {500 throw Error( "If the root does not have an updateQueue, we should have already bailed out. This error is likely caused by a bug in React. Please file an issue." );501 }502 }503 var nextProps = workInProgress.pendingProps;504 var prevState = workInProgress.memoizedState;505 var prevChildren = prevState !== null ? prevState.element : null;506 cloneUpdateQueue(current, workInProgress);507 processUpdateQueue(workInProgress, nextProps, null, renderLanes);508 var nextState = workInProgress.memoizedState; // Caution: React DevTools currently depends on this property509 // being called "element".510 var nextChildren = nextState.element;511 if (nextChildren === prevChildren) {512 resetHydrationState();513 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);514 }515 var root = workInProgress.stateNode;516 if (root.hydrate && enterHydrationState(workInProgress)) {517 // If we don't have any current children this might be the first pass.518 // We always try to hydrate. If this isn't a hydration pass there won't519 // be any children to hydrate which is effectively the same thing as520 // not hydrating.521 {522 var mutableSourceEagerHydrationData = root.mutableSourceEagerHydrationData;523 if (mutableSourceEagerHydrationData != null) {524 for (var i = 0; i < mutableSourceEagerHydrationData.length; i += 2) {525 var mutableSource = mutableSourceEagerHydrationData[i];526 var version = mutableSourceEagerHydrationData[i + 1];527 setWorkInProgressVersion(mutableSource, version);528 }529 }530 }531 var child = mountChildFibers(workInProgress, null, nextChildren, renderLanes);532 workInProgress.child = child;533 var node = child;534 while (node) {535 // Mark each child as hydrating. This is a fast path to know whether this536 // tree is part of a hydrating tree. This is used to determine if a child537 // node has fully mounted yet, and for scheduling event replaying.538 // Conceptually this is similar to Placement in that a new subtree is539 // inserted into the React tree here. It just happens to not need DOM540 // mutations because it already exists.541 node.flags = node.flags & ~Placement | Hydrating;542 node = node.sibling;543 }544 } else {545 // Otherwise reset hydration state in case we aborted and resumed another546 // root.547 reconcileChildren(current, workInProgress, nextChildren, renderLanes);548 resetHydrationState();549 }550 return workInProgress.child;551 }552 function updateHostComponent(current, workInProgress, renderLanes) {553 pushHostContext(workInProgress);554 if (current === null) {555 tryToClaimNextHydratableInstance(workInProgress);556 }557 var type = workInProgress.type;558 var nextProps = workInProgress.pendingProps;559 var prevProps = current !== null ? current.memoizedProps : null;560 var nextChildren = nextProps.children;561 var isDirectTextChild = shouldSetTextContent(type, nextProps);562 if (isDirectTextChild) {563 // We special case a direct text child of a host node. This is a common564 // case. We won't handle it as a reified child. We will instead handle565 // this in the host environment that also has access to this prop. That566 // avoids allocating another HostText fiber and traversing it.567 nextChildren = null;568 } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) {569 // If we're switching from a direct text child to a normal child, or to570 // empty, we need to schedule the text content to be reset.571 workInProgress.flags |= ContentReset;572 }573 markRef(current, workInProgress);574 reconcileChildren(current, workInProgress, nextChildren, renderLanes);575 return workInProgress.child;576 }577 function updateHostText(current, workInProgress) {578 if (current === null) {579 tryToClaimNextHydratableInstance(workInProgress);580 } // Nothing to do here. This is terminal. We'll do the completion step581 // immediately after.582 return null;583 }584 function mountLazyComponent(_current, workInProgress, elementType, updateLanes, renderLanes) {585 if (_current !== null) {586 // A lazy component only mounts if it suspended inside a non-587 // concurrent tree, in an inconsistent state. We want to treat it like588 // a new mount, even though an empty version of it already committed.589 // Disconnect the alternate pointers.590 _current.alternate = null;591 workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect592 workInProgress.flags |= Placement;593 }594 var props = workInProgress.pendingProps;595 var lazyComponent = elementType;596 var payload = lazyComponent._payload;597 var init = lazyComponent._init;598 var Component = init(payload); // Store the unwrapped component in the type.599 workInProgress.type = Component;600 var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component);601 var resolvedProps = resolveDefaultProps(Component, props);602 var child;603 switch (resolvedTag) {604 case FunctionComponent:605 {606 {607 validateFunctionComponentInDev(workInProgress, Component);608 workInProgress.type = Component = resolveFunctionForHotReloading(Component);609 }610 child = updateFunctionComponent(null, workInProgress, Component, resolvedProps, renderLanes);611 return child;612 }613 case ClassComponent:614 {615 {616 workInProgress.type = Component = resolveClassForHotReloading(Component);617 }618 child = updateClassComponent(null, workInProgress, Component, resolvedProps, renderLanes);619 return child;620 }621 case ForwardRef:622 {623 {624 workInProgress.type = Component = resolveForwardRefForHotReloading(Component);625 }626 child = updateForwardRef(null, workInProgress, Component, resolvedProps, renderLanes);627 return child;628 }629 case MemoComponent:630 {631 {632 if (workInProgress.type !== workInProgress.elementType) {633 var outerPropTypes = Component.propTypes;634 if (outerPropTypes) {635 checkPropTypes(outerPropTypes, resolvedProps, // Resolved for outer only636 'prop', getComponentName(Component));637 }638 }639 }640 child = updateMemoComponent(null, workInProgress, Component, resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too641 updateLanes, renderLanes);642 return child;643 }644 case Block:645 {646 {647 // TODO: Resolve for Hot Reloading.648 child = updateBlock(null, workInProgress, Component, props, renderLanes);649 return child;650 }651 }652 }653 var hint = '';654 {655 if (Component !== null && typeof Component === 'object' && Component.$$typeof === REACT_LAZY_TYPE) {656 hint = ' Did you wrap a component in React.lazy() more than once?';657 }658 } // This message intentionally doesn't mention ForwardRef or MemoComponent659 // because the fact that it's a separate type of work is an660 // implementation detail.661 {662 {663 throw Error( "Element type is invalid. Received a promise that resolves to: " + Component + ". Lazy element type must resolve to a class or function." + hint );664 }665 }666 }667 function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderLanes) {668 if (_current !== null) {669 // An incomplete component only mounts if it suspended inside a non-670 // concurrent tree, in an inconsistent state. We want to treat it like671 // a new mount, even though an empty version of it already committed.672 // Disconnect the alternate pointers.673 _current.alternate = null;674 workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect675 workInProgress.flags |= Placement;676 } // Promote the fiber to a class and try rendering again.677 workInProgress.tag = ClassComponent; // The rest of this function is a fork of `updateClassComponent`678 // Push context providers early to prevent context stack mismatches.679 // During mounting we don't know the child context yet as the instance doesn't exist.680 // We will invalidate the child context in finishClassComponent() right after rendering.681 var hasContext;682 if (isContextProvider(Component)) {683 hasContext = true;684 pushContextProvider(workInProgress);685 } else {686 hasContext = false;687 }688 prepareToReadContext(workInProgress, renderLanes);689 constructClassInstance(workInProgress, Component, nextProps);690 mountClassInstance(workInProgress, Component, nextProps, renderLanes);691 return finishClassComponent(null, workInProgress, Component, true, hasContext, renderLanes);692 }693 function mountIndeterminateComponent(_current, workInProgress, Component, renderLanes) {694 if (_current !== null) {695 // An indeterminate component only mounts if it suspended inside a non-696 // concurrent tree, in an inconsistent state. We want to treat it like697 // a new mount, even though an empty version of it already committed.698 // Disconnect the alternate pointers.699 _current.alternate = null;700 workInProgress.alternate = null; // Since this is conceptually a new fiber, schedule a Placement effect701 workInProgress.flags |= Placement;702 }703 var props = workInProgress.pendingProps;704 var context;705 {706 var unmaskedContext = getUnmaskedContext(workInProgress, Component, false);707 context = getMaskedContext(workInProgress, unmaskedContext);708 }709 prepareToReadContext(workInProgress, renderLanes);710 var value;711 {712 if (Component.prototype && typeof Component.prototype.render === 'function') {713 var componentName = getComponentName(Component) || 'Unknown';714 if (!didWarnAboutBadClass[componentName]) {715 error("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);716 didWarnAboutBadClass[componentName] = true;717 }718 }719 if (workInProgress.mode & StrictMode) {720 ReactStrictModeWarnings.recordLegacyContextWarning(workInProgress, null);721 }722 setIsRendering(true);723 ReactCurrentOwner$1.current = workInProgress;724 value = renderWithHooks(null, workInProgress, Component, props, context, renderLanes);725 setIsRendering(false);726 } // React DevTools reads this flag.727 workInProgress.flags |= PerformedWork;728 {729 // Support for module components is deprecated and is removed behind a flag.730 // Whether or not it would crash later, we want to show a good message in DEV first.731 if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {732 var _componentName = getComponentName(Component) || 'Unknown';733 if (!didWarnAboutModulePatternComponent[_componentName]) {734 error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + 'cannot be called with `new` by React.', _componentName, _componentName, _componentName);735 didWarnAboutModulePatternComponent[_componentName] = true;736 }737 }738 }739 if ( // Run these checks in production only if the flag is off.740 // Eventually we'll delete this branch altogether.741 typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) {742 {743 var _componentName2 = getComponentName(Component) || 'Unknown';744 if (!didWarnAboutModulePatternComponent[_componentName2]) {745 error('The <%s /> component appears to be a function component that returns a class instance. ' + 'Change %s to a class that extends React.Component instead. ' + "If you can't use a class try assigning the prototype on the function as a workaround. " + "`%s.prototype = React.Component.prototype`. Don't use an arrow function since it " + 'cannot be called with `new` by React.', _componentName2, _componentName2, _componentName2);746 didWarnAboutModulePatternComponent[_componentName2] = true;747 }748 } // Proceed under the assumption that this is a class instance749 workInProgress.tag = ClassComponent; // Throw out any hooks that were used.750 workInProgress.memoizedState = null;751 workInProgress.updateQueue = null; // Push context providers early to prevent context stack mismatches.752 // During mounting we don't know the child context yet as the instance doesn't exist.753 // We will invalidate the child context in finishClassComponent() right after rendering.754 var hasContext = false;755 if (isContextProvider(Component)) {756 hasContext = true;757 pushContextProvider(workInProgress);758 } else {759 hasContext = false;760 }761 workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null;762 initializeUpdateQueue(workInProgress);763 var getDerivedStateFromProps = Component.getDerivedStateFromProps;764 if (typeof getDerivedStateFromProps === 'function') {765 applyDerivedStateFromProps(workInProgress, Component, getDerivedStateFromProps, props);766 }767 adoptClassInstance(workInProgress, value);768 mountClassInstance(workInProgress, Component, props, renderLanes);769 return finishClassComponent(null, workInProgress, Component, true, hasContext, renderLanes);770 } else {771 // Proceed under the assumption that this is a function component772 workInProgress.tag = FunctionComponent;773 {774 if ( workInProgress.mode & StrictMode) {775 disableLogs();776 try {777 value = renderWithHooks(null, workInProgress, Component, props, context, renderLanes);778 } finally {779 reenableLogs();780 }781 }782 }783 reconcileChildren(null, workInProgress, value, renderLanes);784 {785 validateFunctionComponentInDev(workInProgress, Component);786 }787 return workInProgress.child;788 }789 }790 function validateFunctionComponentInDev(workInProgress, Component) {791 {792 if (Component) {793 if (Component.childContextTypes) {794 error('%s(...): childContextTypes cannot be defined on a function component.', Component.displayName || Component.name || 'Component');795 }796 }797 if (workInProgress.ref !== null) {798 var info = '';799 var ownerName = getCurrentFiberOwnerNameInDevOrNull();800 if (ownerName) {801 info += '\n\nCheck the render method of `' + ownerName + '`.';802 }803 var warningKey = ownerName || workInProgress._debugID || '';804 var debugSource = workInProgress._debugSource;805 if (debugSource) {806 warningKey = debugSource.fileName + ':' + debugSource.lineNumber;807 }808 if (!didWarnAboutFunctionRefs[warningKey]) {809 didWarnAboutFunctionRefs[warningKey] = true;810 error('Function components cannot be given refs. ' + 'Attempts to access this ref will fail. ' + 'Did you mean to use React.forwardRef()?%s', info);811 }812 }813 if (typeof Component.getDerivedStateFromProps === 'function') {814 var _componentName3 = getComponentName(Component) || 'Unknown';815 if (!didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3]) {816 error('%s: Function components do not support getDerivedStateFromProps.', _componentName3);817 didWarnAboutGetDerivedStateOnFunctionComponent[_componentName3] = true;818 }819 }820 if (typeof Component.contextType === 'object' && Component.contextType !== null) {821 var _componentName4 = getComponentName(Component) || 'Unknown';822 if (!didWarnAboutContextTypeOnFunctionComponent[_componentName4]) {823 error('%s: Function components do not support contextType.', _componentName4);824 didWarnAboutContextTypeOnFunctionComponent[_componentName4] = true;825 }826 }827 }828 }829 var SUSPENDED_MARKER = {830 dehydrated: null,831 retryLane: NoLane832 };833 function mountSuspenseOffscreenState(renderLanes) {834 return {835 baseLanes: renderLanes836 };837 }838 function updateSuspenseOffscreenState(prevOffscreenState, renderLanes) {839 return {840 baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes)841 };842 } // TODO: Probably should inline this back843 function shouldRemainOnFallback(suspenseContext, current, workInProgress, renderLanes) {844 // If we're already showing a fallback, there are cases where we need to845 // remain on that fallback regardless of whether the content has resolved.846 // For example, SuspenseList coordinates when nested content appears.847 if (current !== null) {848 var suspenseState = current.memoizedState;849 if (suspenseState === null) {850 // Currently showing content. Don't hide it, even if ForceSuspenseFallack851 // is true. More precise name might be "ForceRemainSuspenseFallback".852 // Note: This is a factoring smell. Can't remain on a fallback if there's853 // no fallback to remain on.854 return false;855 }856 } // Not currently showing content. Consult the Suspense context.857 return hasSuspenseContext(suspenseContext, ForceSuspenseFallback);858 }859 function getRemainingWorkInPrimaryTree(current, renderLanes) {860 // TODO: Should not remove render lanes that were pinged during this render861 return removeLanes(current.childLanes, renderLanes);862 }863 function updateSuspenseComponent(current, workInProgress, renderLanes) {864 var nextProps = workInProgress.pendingProps; // This is used by DevTools to force a boundary to suspend.865 {866 if (shouldSuspend(workInProgress)) {867 workInProgress.flags |= DidCapture;868 }869 }870 var suspenseContext = suspenseStackCursor.current;871 var showFallback = false;872 var didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;873 if (didSuspend || shouldRemainOnFallback(suspenseContext, current)) {874 // Something in this boundary's subtree already suspended. Switch to875 // rendering the fallback children.876 showFallback = true;877 workInProgress.flags &= ~DidCapture;878 } else {879 // Attempting the main content880 if (current === null || current.memoizedState !== null) {881 // This is a new mount or this boundary is already showing a fallback state.882 // Mark this subtree context as having at least one invisible parent that could883 // handle the fallback state.884 // Boundaries without fallbacks or should be avoided are not considered since885 // they cannot handle preferred fallback states.886 if (nextProps.fallback !== undefined && nextProps.unstable_avoidThisFallback !== true) {887 suspenseContext = addSubtreeSuspenseContext(suspenseContext, InvisibleParentSuspenseContext);888 }889 }890 }891 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);892 pushSuspenseContext(workInProgress, suspenseContext); // OK, the next part is confusing. We're about to reconcile the Suspense893 // boundary's children. This involves some custom reconcilation logic. Two894 // main reasons this is so complicated.895 //896 // First, Legacy Mode has different semantics for backwards compatibility. The897 // primary tree will commit in an inconsistent state, so when we do the898 // second pass to render the fallback, we do some exceedingly, uh, clever899 // hacks to make that not totally break. Like transferring effects and900 // deletions from hidden tree. In Concurrent Mode, it's much simpler,901 // because we bailout on the primary tree completely and leave it in its old902 // state, no effects. Same as what we do for Offscreen (except that903 // Offscreen doesn't have the first render pass).904 //905 // Second is hydration. During hydration, the Suspense fiber has a slightly906 // different layout, where the child points to a dehydrated fragment, which907 // contains the DOM rendered by the server.908 //909 // Third, even if you set all that aside, Suspense is like error boundaries in910 // that we first we try to render one tree, and if that fails, we render again911 // and switch to a different tree. Like a try/catch block. So we have to track912 // which branch we're currently rendering. Ideally we would model this using913 // a stack.914 if (current === null) {915 // Initial mount916 // If we're currently hydrating, try to hydrate this boundary.917 // But only if this has a fallback.918 if (nextProps.fallback !== undefined) {919 tryToClaimNextHydratableInstance(workInProgress); // This could've been a dehydrated suspense component.920 {921 var suspenseState = workInProgress.memoizedState;922 if (suspenseState !== null) {923 var dehydrated = suspenseState.dehydrated;924 if (dehydrated !== null) {925 return mountDehydratedSuspenseComponent(workInProgress, dehydrated);926 }927 }928 }929 }930 var nextPrimaryChildren = nextProps.children;931 var nextFallbackChildren = nextProps.fallback;932 if (showFallback) {933 var fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes);934 var primaryChildFragment = workInProgress.child;935 primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes);936 workInProgress.memoizedState = SUSPENDED_MARKER;937 return fallbackFragment;938 } else if (typeof nextProps.unstable_expectedLoadTime === 'number') {939 // This is a CPU-bound tree. Skip this tree and show a placeholder to940 // unblock the surrounding content. Then immediately retry after the941 // initial commit.942 var _fallbackFragment = mountSuspenseFallbackChildren(workInProgress, nextPrimaryChildren, nextFallbackChildren, renderLanes);943 var _primaryChildFragment = workInProgress.child;944 _primaryChildFragment.memoizedState = mountSuspenseOffscreenState(renderLanes);945 workInProgress.memoizedState = SUSPENDED_MARKER; // Since nothing actually suspended, there will nothing to ping this to946 // get it started back up to attempt the next item. While in terms of947 // priority this work has the same priority as this current render, it's948 // not part of the same transition once the transition has committed. If949 // it's sync, we still want to yield so that it can be painted.950 // Conceptually, this is really the same as pinging. We can use any951 // RetryLane even if it's the one currently rendering since we're leaving952 // it behind on this node.953 workInProgress.lanes = SomeRetryLane;954 {955 markSpawnedWork(SomeRetryLane);956 }957 return _fallbackFragment;958 } else {959 return mountSuspensePrimaryChildren(workInProgress, nextPrimaryChildren, renderLanes);960 }961 } else {962 // This is an update.963 // If the current fiber has a SuspenseState, that means it's already showing964 // a fallback.965 var prevState = current.memoizedState;966 if (prevState !== null) {967 // The current tree is already showing a fallback968 // Special path for hydration969 {970 var _dehydrated = prevState.dehydrated;971 if (_dehydrated !== null) {972 if (!didSuspend) {973 return updateDehydratedSuspenseComponent(current, workInProgress, _dehydrated, prevState, renderLanes);974 } else if (workInProgress.memoizedState !== null) {975 // Something suspended and we should still be in dehydrated mode.976 // Leave the existing child in place.977 workInProgress.child = current.child; // The dehydrated completion pass expects this flag to be there978 // but the normal suspense pass doesn't.979 workInProgress.flags |= DidCapture;980 return null;981 } else {982 // Suspended but we should no longer be in dehydrated mode.983 // Therefore we now have to render the fallback.984 var _nextPrimaryChildren = nextProps.children;985 var _nextFallbackChildren = nextProps.fallback;986 var fallbackChildFragment = mountSuspenseFallbackAfterRetryWithoutHydrating(current, workInProgress, _nextPrimaryChildren, _nextFallbackChildren, renderLanes);987 var _primaryChildFragment2 = workInProgress.child;988 _primaryChildFragment2.memoizedState = mountSuspenseOffscreenState(renderLanes);989 workInProgress.memoizedState = SUSPENDED_MARKER;990 return fallbackChildFragment;991 }992 }993 }994 if (showFallback) {995 var _nextFallbackChildren2 = nextProps.fallback;996 var _nextPrimaryChildren2 = nextProps.children;997 var _fallbackChildFragment = updateSuspenseFallbackChildren(current, workInProgress, _nextPrimaryChildren2, _nextFallbackChildren2, renderLanes);998 var _primaryChildFragment3 = workInProgress.child;999 var prevOffscreenState = current.child.memoizedState;1000 _primaryChildFragment3.memoizedState = prevOffscreenState === null ? mountSuspenseOffscreenState(renderLanes) : updateSuspenseOffscreenState(prevOffscreenState, renderLanes);1001 _primaryChildFragment3.childLanes = getRemainingWorkInPrimaryTree(current, renderLanes);1002 workInProgress.memoizedState = SUSPENDED_MARKER;1003 return _fallbackChildFragment;1004 } else {1005 var _nextPrimaryChildren3 = nextProps.children;1006 var _primaryChildFragment4 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren3, renderLanes);1007 workInProgress.memoizedState = null;1008 return _primaryChildFragment4;1009 }1010 } else {1011 // The current tree is not already showing a fallback.1012 if (showFallback) {1013 // Timed out.1014 var _nextFallbackChildren3 = nextProps.fallback;1015 var _nextPrimaryChildren4 = nextProps.children;1016 var _fallbackChildFragment2 = updateSuspenseFallbackChildren(current, workInProgress, _nextPrimaryChildren4, _nextFallbackChildren3, renderLanes);1017 var _primaryChildFragment5 = workInProgress.child;1018 var _prevOffscreenState = current.child.memoizedState;1019 _primaryChildFragment5.memoizedState = _prevOffscreenState === null ? mountSuspenseOffscreenState(renderLanes) : updateSuspenseOffscreenState(_prevOffscreenState, renderLanes);1020 _primaryChildFragment5.childLanes = getRemainingWorkInPrimaryTree(current, renderLanes); // Skip the primary children, and continue working on the1021 // fallback children.1022 workInProgress.memoizedState = SUSPENDED_MARKER;1023 return _fallbackChildFragment2;1024 } else {1025 // Still haven't timed out. Continue rendering the children, like we1026 // normally do.1027 var _nextPrimaryChildren5 = nextProps.children;1028 var _primaryChildFragment6 = updateSuspensePrimaryChildren(current, workInProgress, _nextPrimaryChildren5, renderLanes);1029 workInProgress.memoizedState = null;1030 return _primaryChildFragment6;1031 }1032 }1033 }1034 }1035 function mountSuspensePrimaryChildren(workInProgress, primaryChildren, renderLanes) {1036 var mode = workInProgress.mode;1037 var primaryChildProps = {1038 mode: 'visible',1039 children: primaryChildren1040 };1041 var primaryChildFragment = createFiberFromOffscreen(primaryChildProps, mode, renderLanes, null);1042 primaryChildFragment.return = workInProgress;1043 workInProgress.child = primaryChildFragment;1044 return primaryChildFragment;1045 }1046 function mountSuspenseFallbackChildren(workInProgress, primaryChildren, fallbackChildren, renderLanes) {1047 var mode = workInProgress.mode;1048 var progressedPrimaryFragment = workInProgress.child;1049 var primaryChildProps = {1050 mode: 'hidden',1051 children: primaryChildren1052 };1053 var primaryChildFragment;1054 var fallbackChildFragment;1055 if ((mode & BlockingMode) === NoMode && progressedPrimaryFragment !== null) {1056 // In legacy mode, we commit the primary tree as if it successfully1057 // completed, even though it's in an inconsistent state.1058 primaryChildFragment = progressedPrimaryFragment;1059 primaryChildFragment.childLanes = NoLanes;1060 primaryChildFragment.pendingProps = primaryChildProps;1061 if ( workInProgress.mode & ProfileMode) {1062 // Reset the durations from the first pass so they aren't included in the1063 // final amounts. This seems counterintuitive, since we're intentionally1064 // not measuring part of the render phase, but this makes it match what we1065 // do in Concurrent Mode.1066 primaryChildFragment.actualDuration = 0;1067 primaryChildFragment.actualStartTime = -1;1068 primaryChildFragment.selfBaseDuration = 0;1069 primaryChildFragment.treeBaseDuration = 0;1070 }1071 fallbackChildFragment = createFiberFromFragment(fallbackChildren, mode, renderLanes, null);1072 } else {1073 primaryChildFragment = createFiberFromOffscreen(primaryChildProps, mode, NoLanes, null);1074 fallbackChildFragment = createFiberFromFragment(fallbackChildren, mode, renderLanes, null);1075 }1076 primaryChildFragment.return = workInProgress;1077 fallbackChildFragment.return = workInProgress;1078 primaryChildFragment.sibling = fallbackChildFragment;1079 workInProgress.child = primaryChildFragment;1080 return fallbackChildFragment;1081 }1082 function createWorkInProgressOffscreenFiber(current, offscreenProps) {1083 // The props argument to `createWorkInProgress` is `any` typed, so we use this1084 // wrapper function to constrain it.1085 return createWorkInProgress(current, offscreenProps);1086 }1087 function updateSuspensePrimaryChildren(current, workInProgress, primaryChildren, renderLanes) {1088 var currentPrimaryChildFragment = current.child;1089 var currentFallbackChildFragment = currentPrimaryChildFragment.sibling;1090 var primaryChildFragment = createWorkInProgressOffscreenFiber(currentPrimaryChildFragment, {1091 mode: 'visible',1092 children: primaryChildren1093 });1094 if ((workInProgress.mode & BlockingMode) === NoMode) {1095 primaryChildFragment.lanes = renderLanes;1096 }1097 primaryChildFragment.return = workInProgress;1098 primaryChildFragment.sibling = null;1099 if (currentFallbackChildFragment !== null) {1100 // Delete the fallback child fragment1101 currentFallbackChildFragment.nextEffect = null;1102 currentFallbackChildFragment.flags = Deletion;1103 workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChildFragment;1104 }1105 workInProgress.child = primaryChildFragment;1106 return primaryChildFragment;1107 }1108 function updateSuspenseFallbackChildren(current, workInProgress, primaryChildren, fallbackChildren, renderLanes) {1109 var mode = workInProgress.mode;1110 var currentPrimaryChildFragment = current.child;1111 var currentFallbackChildFragment = currentPrimaryChildFragment.sibling;1112 var primaryChildProps = {1113 mode: 'hidden',1114 children: primaryChildren1115 };1116 var primaryChildFragment;1117 if ( // In legacy mode, we commit the primary tree as if it successfully1118 // completed, even though it's in an inconsistent state.1119 (mode & BlockingMode) === NoMode && // Make sure we're on the second pass, i.e. the primary child fragment was1120 // already cloned. In legacy mode, the only case where this isn't true is1121 // when DevTools forces us to display a fallback; we skip the first render1122 // pass entirely and go straight to rendering the fallback. (In Concurrent1123 // Mode, SuspenseList can also trigger this scenario, but this is a legacy-1124 // only codepath.)1125 workInProgress.child !== currentPrimaryChildFragment) {1126 var progressedPrimaryFragment = workInProgress.child;1127 primaryChildFragment = progressedPrimaryFragment;1128 primaryChildFragment.childLanes = NoLanes;1129 primaryChildFragment.pendingProps = primaryChildProps;1130 if ( workInProgress.mode & ProfileMode) {1131 // Reset the durations from the first pass so they aren't included in the1132 // final amounts. This seems counterintuitive, since we're intentionally1133 // not measuring part of the render phase, but this makes it match what we1134 // do in Concurrent Mode.1135 primaryChildFragment.actualDuration = 0;1136 primaryChildFragment.actualStartTime = -1;1137 primaryChildFragment.selfBaseDuration = currentPrimaryChildFragment.selfBaseDuration;1138 primaryChildFragment.treeBaseDuration = currentPrimaryChildFragment.treeBaseDuration;1139 } // The fallback fiber was added as a deletion effect during the first pass.1140 // However, since we're going to remain on the fallback, we no longer want1141 // to delete it. So we need to remove it from the list. Deletions are stored1142 // on the same list as effects. We want to keep the effects from the primary1143 // tree. So we copy the primary child fragment's effect list, which does not1144 // include the fallback deletion effect.1145 var progressedLastEffect = primaryChildFragment.lastEffect;1146 if (progressedLastEffect !== null) {1147 workInProgress.firstEffect = primaryChildFragment.firstEffect;1148 workInProgress.lastEffect = progressedLastEffect;1149 progressedLastEffect.nextEffect = null;1150 } else {1151 // TODO: Reset this somewhere else? Lol legacy mode is so weird.1152 workInProgress.firstEffect = workInProgress.lastEffect = null;1153 }1154 } else {1155 primaryChildFragment = createWorkInProgressOffscreenFiber(currentPrimaryChildFragment, primaryChildProps);1156 }1157 var fallbackChildFragment;1158 if (currentFallbackChildFragment !== null) {1159 fallbackChildFragment = createWorkInProgress(currentFallbackChildFragment, fallbackChildren);1160 } else {1161 fallbackChildFragment = createFiberFromFragment(fallbackChildren, mode, renderLanes, null); // Needs a placement effect because the parent (the Suspense boundary) already1162 // mounted but this is a new fiber.1163 fallbackChildFragment.flags |= Placement;1164 }1165 fallbackChildFragment.return = workInProgress;1166 primaryChildFragment.return = workInProgress;1167 primaryChildFragment.sibling = fallbackChildFragment;1168 workInProgress.child = primaryChildFragment;1169 return fallbackChildFragment;1170 }1171 function retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes) {1172 // This will add the old fiber to the deletion list1173 reconcileChildFibers(workInProgress, current.child, null, renderLanes); // We're now not suspended nor dehydrated.1174 var nextProps = workInProgress.pendingProps;1175 var primaryChildren = nextProps.children;1176 var primaryChildFragment = mountSuspensePrimaryChildren(workInProgress, primaryChildren, renderLanes); // Needs a placement effect because the parent (the Suspense boundary) already1177 // mounted but this is a new fiber.1178 primaryChildFragment.flags |= Placement;1179 workInProgress.memoizedState = null;1180 return primaryChildFragment;1181 }1182 function mountSuspenseFallbackAfterRetryWithoutHydrating(current, workInProgress, primaryChildren, fallbackChildren, renderLanes) {1183 var mode = workInProgress.mode;1184 var primaryChildFragment = createFiberFromOffscreen(primaryChildren, mode, NoLanes, null);1185 var fallbackChildFragment = createFiberFromFragment(fallbackChildren, mode, renderLanes, null); // Needs a placement effect because the parent (the Suspense1186 // boundary) already mounted but this is a new fiber.1187 fallbackChildFragment.flags |= Placement;1188 primaryChildFragment.return = workInProgress;1189 fallbackChildFragment.return = workInProgress;1190 primaryChildFragment.sibling = fallbackChildFragment;1191 workInProgress.child = primaryChildFragment;1192 if ((workInProgress.mode & BlockingMode) !== NoMode) {1193 // We will have dropped the effect list which contains the1194 // deletion. We need to reconcile to delete the current child.1195 reconcileChildFibers(workInProgress, current.child, null, renderLanes);1196 }1197 return fallbackChildFragment;1198 }1199 function mountDehydratedSuspenseComponent(workInProgress, suspenseInstance, renderLanes) {1200 // During the first pass, we'll bail out and not drill into the children.1201 // Instead, we'll leave the content in place and try to hydrate it later.1202 if ((workInProgress.mode & BlockingMode) === NoMode) {1203 {1204 error('Cannot hydrate Suspense in legacy mode. Switch from ' + 'ReactDOM.hydrate(element, container) to ' + 'ReactDOM.createBlockingRoot(container, { hydrate: true })' + '.render(element) or remove the Suspense components from ' + 'the server rendered components.');1205 }1206 workInProgress.lanes = laneToLanes(SyncLane);1207 } else if (isSuspenseInstanceFallback(suspenseInstance)) {1208 // This is a client-only boundary. Since we won't get any content from the server1209 // for this, we need to schedule that at a higher priority based on when it would1210 // have timed out. In theory we could render it in this pass but it would have the1211 // wrong priority associated with it and will prevent hydration of parent path.1212 // Instead, we'll leave work left on it to render it in a separate commit.1213 // TODO This time should be the time at which the server rendered response that is1214 // a parent to this boundary was displayed. However, since we currently don't have1215 // a protocol to transfer that time, we'll just estimate it by using the current1216 // time. This will mean that Suspense timeouts are slightly shifted to later than1217 // they should be.1218 // Schedule a normal pri update to render this content.1219 {1220 markSpawnedWork(DefaultHydrationLane);1221 }1222 workInProgress.lanes = laneToLanes(DefaultHydrationLane);1223 } else {1224 // We'll continue hydrating the rest at offscreen priority since we'll already1225 // be showing the right content coming from the server, it is no rush.1226 workInProgress.lanes = laneToLanes(OffscreenLane);1227 {1228 markSpawnedWork(OffscreenLane);1229 }1230 }1231 return null;1232 }1233 function updateDehydratedSuspenseComponent(current, workInProgress, suspenseInstance, suspenseState, renderLanes) {1234 // We should never be hydrating at this point because it is the first pass,1235 // but after we've already committed once.1236 warnIfHydrating();1237 if ((getExecutionContext() & RetryAfterError) !== NoContext) {1238 return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes);1239 }1240 if ((workInProgress.mode & BlockingMode) === NoMode) {1241 return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes);1242 }1243 if (isSuspenseInstanceFallback(suspenseInstance)) {1244 // This boundary is in a permanent fallback state. In this case, we'll never1245 // get an update and we'll never be able to hydrate the final content. Let's just try the1246 // client side render instead.1247 return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes);1248 } // We use lanes to indicate that a child might depend on context, so if1249 // any context has changed, we need to treat is as if the input might have changed.1250 var hasContextChanged = includesSomeLane(renderLanes, current.childLanes);1251 if (didReceiveUpdate || hasContextChanged) {1252 // This boundary has changed since the first render. This means that we are now unable to1253 // hydrate it. We might still be able to hydrate it using a higher priority lane.1254 var root = getWorkInProgressRoot();1255 if (root !== null) {1256 var attemptHydrationAtLane = getBumpedLaneForHydration(root, renderLanes);1257 if (attemptHydrationAtLane !== NoLane && attemptHydrationAtLane !== suspenseState.retryLane) {1258 // Intentionally mutating since this render will get interrupted. This1259 // is one of the very rare times where we mutate the current tree1260 // during the render phase.1261 suspenseState.retryLane = attemptHydrationAtLane; // TODO: Ideally this would inherit the event time of the current render1262 var eventTime = NoTimestamp;1263 scheduleUpdateOnFiber(current, attemptHydrationAtLane, eventTime);1264 }1265 } // If we have scheduled higher pri work above, this will probably just abort the render1266 // since we now have higher priority work, but in case it doesn't, we need to prepare to1267 // render something, if we time out. Even if that requires us to delete everything and1268 // skip hydration.1269 // Delay having to do this as long as the suspense timeout allows us.1270 renderDidSuspendDelayIfPossible();1271 return retrySuspenseComponentWithoutHydrating(current, workInProgress, renderLanes);1272 } else if (isSuspenseInstancePending(suspenseInstance)) {1273 // This component is still pending more data from the server, so we can't hydrate its1274 // content. We treat it as if this component suspended itself. It might seem as if1275 // we could just try to render it client-side instead. However, this will perform a1276 // lot of unnecessary work and is unlikely to complete since it often will suspend1277 // on missing data anyway. Additionally, the server might be able to render more1278 // than we can on the client yet. In that case we'd end up with more fallback states1279 // on the client than if we just leave it alone. If the server times out or errors1280 // these should update this boundary to the permanent Fallback state instead.1281 // Mark it as having captured (i.e. suspended).1282 workInProgress.flags |= DidCapture; // Leave the child in place. I.e. the dehydrated fragment.1283 workInProgress.child = current.child; // Register a callback to retry this boundary once the server has sent the result.1284 var retry = retryDehydratedSuspenseBoundary.bind(null, current);1285 {1286 retry = unstable_wrap(retry);1287 }1288 registerSuspenseInstanceRetry(suspenseInstance, retry);1289 return null;1290 } else {1291 // This is the first attempt.1292 reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress, suspenseInstance);1293 var nextProps = workInProgress.pendingProps;1294 var primaryChildren = nextProps.children;1295 var primaryChildFragment = mountSuspensePrimaryChildren(workInProgress, primaryChildren, renderLanes); // Mark the children as hydrating. This is a fast path to know whether this1296 // tree is part of a hydrating tree. This is used to determine if a child1297 // node has fully mounted yet, and for scheduling event replaying.1298 // Conceptually this is similar to Placement in that a new subtree is1299 // inserted into the React tree here. It just happens to not need DOM1300 // mutations because it already exists.1301 primaryChildFragment.flags |= Hydrating;1302 return primaryChildFragment;1303 }1304 }1305 function scheduleWorkOnFiber(fiber, renderLanes) {1306 fiber.lanes = mergeLanes(fiber.lanes, renderLanes);1307 var alternate = fiber.alternate;1308 if (alternate !== null) {1309 alternate.lanes = mergeLanes(alternate.lanes, renderLanes);1310 }1311 scheduleWorkOnParentPath(fiber.return, renderLanes);1312 }1313 function propagateSuspenseContextChange(workInProgress, firstChild, renderLanes) {1314 // Mark any Suspense boundaries with fallbacks as having work to do.1315 // If they were previously forced into fallbacks, they may now be able1316 // to unblock.1317 var node = firstChild;1318 while (node !== null) {1319 if (node.tag === SuspenseComponent) {1320 var state = node.memoizedState;1321 if (state !== null) {1322 scheduleWorkOnFiber(node, renderLanes);1323 }1324 } else if (node.tag === SuspenseListComponent) {1325 // If the tail is hidden there might not be an Suspense boundaries1326 // to schedule work on. In this case we have to schedule it on the1327 // list itself.1328 // We don't have to traverse to the children of the list since1329 // the list will propagate the change when it rerenders.1330 scheduleWorkOnFiber(node, renderLanes);1331 } else if (node.child !== null) {1332 node.child.return = node;1333 node = node.child;1334 continue;1335 }1336 if (node === workInProgress) {1337 return;1338 }1339 while (node.sibling === null) {1340 if (node.return === null || node.return === workInProgress) {1341 return;1342 }1343 node = node.return;1344 }1345 node.sibling.return = node.return;1346 node = node.sibling;1347 }1348 }1349 function findLastContentRow(firstChild) {1350 // This is going to find the last row among these children that is already1351 // showing content on the screen, as opposed to being in fallback state or1352 // new. If a row has multiple Suspense boundaries, any of them being in the1353 // fallback state, counts as the whole row being in a fallback state.1354 // Note that the "rows" will be workInProgress, but any nested children1355 // will still be current since we haven't rendered them yet. The mounted1356 // order may not be the same as the new order. We use the new order.1357 var row = firstChild;1358 var lastContentRow = null;1359 while (row !== null) {1360 var currentRow = row.alternate; // New rows can't be content rows.1361 if (currentRow !== null && findFirstSuspended(currentRow) === null) {1362 lastContentRow = row;1363 }1364 row = row.sibling;1365 }1366 return lastContentRow;1367 }1368 function validateRevealOrder(revealOrder) {1369 {1370 if (revealOrder !== undefined && revealOrder !== 'forwards' && revealOrder !== 'backwards' && revealOrder !== 'together' && !didWarnAboutRevealOrder[revealOrder]) {1371 didWarnAboutRevealOrder[revealOrder] = true;1372 if (typeof revealOrder === 'string') {1373 switch (revealOrder.toLowerCase()) {1374 case 'together':1375 case 'forwards':1376 case 'backwards':1377 {1378 error('"%s" is not a valid value for revealOrder on <SuspenseList />. ' + 'Use lowercase "%s" instead.', revealOrder, revealOrder.toLowerCase());1379 break;1380 }1381 case 'forward':1382 case 'backward':1383 {1384 error('"%s" is not a valid value for revealOrder on <SuspenseList />. ' + 'React uses the -s suffix in the spelling. Use "%ss" instead.', revealOrder, revealOrder.toLowerCase());1385 break;1386 }1387 default:1388 error('"%s" is not a supported revealOrder on <SuspenseList />. ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder);1389 break;1390 }1391 } else {1392 error('%s is not a supported value for revealOrder on <SuspenseList />. ' + 'Did you mean "together", "forwards" or "backwards"?', revealOrder);1393 }1394 }1395 }1396 }1397 function validateTailOptions(tailMode, revealOrder) {1398 {1399 if (tailMode !== undefined && !didWarnAboutTailOptions[tailMode]) {1400 if (tailMode !== 'collapsed' && tailMode !== 'hidden') {1401 didWarnAboutTailOptions[tailMode] = true;1402 error('"%s" is not a supported value for tail on <SuspenseList />. ' + 'Did you mean "collapsed" or "hidden"?', tailMode);1403 } else if (revealOrder !== 'forwards' && revealOrder !== 'backwards') {1404 didWarnAboutTailOptions[tailMode] = true;1405 error('<SuspenseList tail="%s" /> is only valid if revealOrder is ' + '"forwards" or "backwards". ' + 'Did you mean to specify revealOrder="forwards"?', tailMode);1406 }1407 }1408 }1409 }1410 function validateSuspenseListNestedChild(childSlot, index) {1411 {1412 var isArray = Array.isArray(childSlot);1413 var isIterable = !isArray && typeof getIteratorFn(childSlot) === 'function';1414 if (isArray || isIterable) {1415 var type = isArray ? 'array' : 'iterable';1416 error('A nested %s was passed to row #%s in <SuspenseList />. Wrap it in ' + 'an additional SuspenseList to configure its revealOrder: ' + '<SuspenseList revealOrder=...> ... ' + '<SuspenseList revealOrder=...>{%s}</SuspenseList> ... ' + '</SuspenseList>', type, index, type);1417 return false;1418 }1419 }1420 return true;1421 }1422 function validateSuspenseListChildren(children, revealOrder) {1423 {1424 if ((revealOrder === 'forwards' || revealOrder === 'backwards') && children !== undefined && children !== null && children !== false) {1425 if (Array.isArray(children)) {1426 for (var i = 0; i < children.length; i++) {1427 if (!validateSuspenseListNestedChild(children[i], i)) {1428 return;1429 }1430 }1431 } else {1432 var iteratorFn = getIteratorFn(children);1433 if (typeof iteratorFn === 'function') {1434 var childrenIterator = iteratorFn.call(children);1435 if (childrenIterator) {1436 var step = childrenIterator.next();1437 var _i = 0;1438 for (; !step.done; step = childrenIterator.next()) {1439 if (!validateSuspenseListNestedChild(step.value, _i)) {1440 return;1441 }1442 _i++;1443 }1444 }1445 } else {1446 error('A single row was passed to a <SuspenseList revealOrder="%s" />. ' + 'This is not useful since it needs multiple rows. ' + 'Did you mean to pass multiple children or an array?', revealOrder);1447 }1448 }1449 }1450 }1451 }1452 function initSuspenseListRenderState(workInProgress, isBackwards, tail, lastContentRow, tailMode, lastEffectBeforeRendering) {1453 var renderState = workInProgress.memoizedState;1454 if (renderState === null) {1455 workInProgress.memoizedState = {1456 isBackwards: isBackwards,1457 rendering: null,1458 renderingStartTime: 0,1459 last: lastContentRow,1460 tail: tail,1461 tailMode: tailMode,1462 lastEffect: lastEffectBeforeRendering1463 };1464 } else {1465 // We can reuse the existing object from previous renders.1466 renderState.isBackwards = isBackwards;1467 renderState.rendering = null;1468 renderState.renderingStartTime = 0;1469 renderState.last = lastContentRow;1470 renderState.tail = tail;1471 renderState.tailMode = tailMode;1472 renderState.lastEffect = lastEffectBeforeRendering;1473 }1474 } // This can end up rendering this component multiple passes.1475 // The first pass splits the children fibers into two sets. A head and tail.1476 // We first render the head. If anything is in fallback state, we do another1477 // pass through beginWork to rerender all children (including the tail) with1478 // the force suspend context. If the first render didn't have anything in1479 // in fallback state. Then we render each row in the tail one-by-one.1480 // That happens in the completeWork phase without going back to beginWork.1481 function updateSuspenseListComponent(current, workInProgress, renderLanes) {1482 var nextProps = workInProgress.pendingProps;1483 var revealOrder = nextProps.revealOrder;1484 var tailMode = nextProps.tail;1485 var newChildren = nextProps.children;1486 validateRevealOrder(revealOrder);1487 validateTailOptions(tailMode, revealOrder);1488 validateSuspenseListChildren(newChildren, revealOrder);1489 reconcileChildren(current, workInProgress, newChildren, renderLanes);1490 var suspenseContext = suspenseStackCursor.current;1491 var shouldForceFallback = hasSuspenseContext(suspenseContext, ForceSuspenseFallback);1492 if (shouldForceFallback) {1493 suspenseContext = setShallowSuspenseContext(suspenseContext, ForceSuspenseFallback);1494 workInProgress.flags |= DidCapture;1495 } else {1496 var didSuspendBefore = current !== null && (current.flags & DidCapture) !== NoFlags;1497 if (didSuspendBefore) {1498 // If we previously forced a fallback, we need to schedule work1499 // on any nested boundaries to let them know to try to render1500 // again. This is the same as context updating.1501 propagateSuspenseContextChange(workInProgress, workInProgress.child, renderLanes);1502 }1503 suspenseContext = setDefaultShallowSuspenseContext(suspenseContext);1504 }1505 pushSuspenseContext(workInProgress, suspenseContext);1506 if ((workInProgress.mode & BlockingMode) === NoMode) {1507 // In legacy mode, SuspenseList doesn't work so we just1508 // use make it a noop by treating it as the default revealOrder.1509 workInProgress.memoizedState = null;1510 } else {1511 switch (revealOrder) {1512 case 'forwards':1513 {1514 var lastContentRow = findLastContentRow(workInProgress.child);1515 var tail;1516 if (lastContentRow === null) {1517 // The whole list is part of the tail.1518 // TODO: We could fast path by just rendering the tail now.1519 tail = workInProgress.child;1520 workInProgress.child = null;1521 } else {1522 // Disconnect the tail rows after the content row.1523 // We're going to render them separately later.1524 tail = lastContentRow.sibling;1525 lastContentRow.sibling = null;1526 }1527 initSuspenseListRenderState(workInProgress, false, // isBackwards1528 tail, lastContentRow, tailMode, workInProgress.lastEffect);1529 break;1530 }1531 case 'backwards':1532 {1533 // We're going to find the first row that has existing content.1534 // At the same time we're going to reverse the list of everything1535 // we pass in the meantime. That's going to be our tail in reverse1536 // order.1537 var _tail = null;1538 var row = workInProgress.child;1539 workInProgress.child = null;1540 while (row !== null) {1541 var currentRow = row.alternate; // New rows can't be content rows.1542 if (currentRow !== null && findFirstSuspended(currentRow) === null) {1543 // This is the beginning of the main content.1544 workInProgress.child = row;1545 break;1546 }1547 var nextRow = row.sibling;1548 row.sibling = _tail;1549 _tail = row;1550 row = nextRow;1551 } // TODO: If workInProgress.child is null, we can continue on the tail immediately.1552 initSuspenseListRenderState(workInProgress, true, // isBackwards1553 _tail, null, // last1554 tailMode, workInProgress.lastEffect);1555 break;1556 }1557 case 'together':1558 {1559 initSuspenseListRenderState(workInProgress, false, // isBackwards1560 null, // tail1561 null, // last1562 undefined, workInProgress.lastEffect);1563 break;1564 }1565 default:1566 {1567 // The default reveal order is the same as not having1568 // a boundary.1569 workInProgress.memoizedState = null;1570 }1571 }1572 }1573 return workInProgress.child;1574 }1575 function updatePortalComponent(current, workInProgress, renderLanes) {1576 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);1577 var nextChildren = workInProgress.pendingProps;1578 if (current === null) {1579 // Portals are special because we don't append the children during mount1580 // but at commit. Therefore we need to track insertions which the normal1581 // flow doesn't do during mount. This doesn't happen at the root because1582 // the root always starts with a "current" with a null child.1583 // TODO: Consider unifying this with how the root works.1584 workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderLanes);1585 } else {1586 reconcileChildren(current, workInProgress, nextChildren, renderLanes);1587 }1588 return workInProgress.child;1589 }1590 var hasWarnedAboutUsingNoValuePropOnContextProvider = false;1591 function updateContextProvider(current, workInProgress, renderLanes) {1592 var providerType = workInProgress.type;1593 var context = providerType._context;1594 var newProps = workInProgress.pendingProps;1595 var oldProps = workInProgress.memoizedProps;1596 var newValue = newProps.value;1597 {1598 if (!('value' in newProps)) {1599 if (!hasWarnedAboutUsingNoValuePropOnContextProvider) {1600 hasWarnedAboutUsingNoValuePropOnContextProvider = true;1601 error('The `value` prop is required for the `<Context.Provider>`. Did you misspell it or forget to pass it?');1602 }1603 }1604 var providerPropTypes = workInProgress.type.propTypes;1605 if (providerPropTypes) {1606 checkPropTypes(providerPropTypes, newProps, 'prop', 'Context.Provider');1607 }1608 }1609 pushProvider(workInProgress, newValue);1610 if (oldProps !== null) {1611 var oldValue = oldProps.value;1612 var changedBits = calculateChangedBits(context, newValue, oldValue);1613 if (changedBits === 0) {1614 // No change. Bailout early if children are the same.1615 if (oldProps.children === newProps.children && !hasContextChanged()) {1616 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1617 }1618 } else {1619 // The context value changed. Search for matching consumers and schedule1620 // them to update.1621 propagateContextChange(workInProgress, context, changedBits, renderLanes);1622 }1623 }1624 var newChildren = newProps.children;1625 reconcileChildren(current, workInProgress, newChildren, renderLanes);1626 return workInProgress.child;1627 }1628 var hasWarnedAboutUsingContextAsConsumer = false;1629 function updateContextConsumer(current, workInProgress, renderLanes) {1630 var context = workInProgress.type; // The logic below for Context differs depending on PROD or DEV mode. In1631 // DEV mode, we create a separate object for Context.Consumer that acts1632 // like a proxy to Context. This proxy object adds unnecessary code in PROD1633 // so we use the old behaviour (Context.Consumer references Context) to1634 // reduce size and overhead. The separate object references context via1635 // a property called "_context", which also gives us the ability to check1636 // in DEV mode if this property exists or not and warn if it does not.1637 {1638 if (context._context === undefined) {1639 // This may be because it's a Context (rather than a Consumer).1640 // Or it may be because it's older React where they're the same thing.1641 // We only want to warn if we're sure it's a new React.1642 if (context !== context.Consumer) {1643 if (!hasWarnedAboutUsingContextAsConsumer) {1644 hasWarnedAboutUsingContextAsConsumer = true;1645 error('Rendering <Context> directly is not supported and will be removed in ' + 'a future major release. Did you mean to render <Context.Consumer> instead?');1646 }1647 }1648 } else {1649 context = context._context;1650 }1651 }1652 var newProps = workInProgress.pendingProps;1653 var render = newProps.children;1654 {1655 if (typeof render !== 'function') {1656 error('A context consumer was rendered with multiple children, or a child ' + "that isn't a function. A context consumer expects a single child " + 'that is a function. If you did pass a function, make sure there ' + 'is no trailing or leading whitespace around it.');1657 }1658 }1659 prepareToReadContext(workInProgress, renderLanes);1660 var newValue = readContext(context, newProps.unstable_observedBits);1661 var newChildren;1662 {1663 ReactCurrentOwner$1.current = workInProgress;1664 setIsRendering(true);1665 newChildren = render(newValue);1666 setIsRendering(false);1667 } // React DevTools reads this flag.1668 workInProgress.flags |= PerformedWork;1669 reconcileChildren(current, workInProgress, newChildren, renderLanes);1670 return workInProgress.child;1671 }1672 function markWorkInProgressReceivedUpdate() {1673 didReceiveUpdate = true;1674 }1675 function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes) {1676 if (current !== null) {1677 // Reuse previous dependencies1678 workInProgress.dependencies = current.dependencies;1679 }1680 {1681 // Don't update "base" render times for bailouts.1682 stopProfilerTimerIfRunning();1683 }1684 markSkippedUpdateLanes(workInProgress.lanes); // Check if the children have any pending work.1685 if (!includesSomeLane(renderLanes, workInProgress.childLanes)) {1686 // The children don't have any work either. We can skip them.1687 // TODO: Once we add back resuming, we should check if the children are1688 // a work-in-progress set. If so, we need to transfer their effects.1689 return null;1690 } else {1691 // This fiber doesn't have work, but its subtree does. Clone the child1692 // fibers and continue.1693 cloneChildFibers(current, workInProgress);1694 return workInProgress.child;1695 }1696 }1697 function remountFiber(current, oldWorkInProgress, newWorkInProgress) {1698 {1699 var returnFiber = oldWorkInProgress.return;1700 if (returnFiber === null) {1701 throw new Error('Cannot swap the root fiber.');1702 } // Disconnect from the old current.1703 // It will get deleted.1704 current.alternate = null;1705 oldWorkInProgress.alternate = null; // Connect to the new tree.1706 newWorkInProgress.index = oldWorkInProgress.index;1707 newWorkInProgress.sibling = oldWorkInProgress.sibling;1708 newWorkInProgress.return = oldWorkInProgress.return;1709 newWorkInProgress.ref = oldWorkInProgress.ref; // Replace the child/sibling pointers above it.1710 if (oldWorkInProgress === returnFiber.child) {1711 returnFiber.child = newWorkInProgress;1712 } else {1713 var prevSibling = returnFiber.child;1714 if (prevSibling === null) {1715 throw new Error('Expected parent to have a child.');1716 }1717 while (prevSibling.sibling !== oldWorkInProgress) {1718 prevSibling = prevSibling.sibling;1719 if (prevSibling === null) {1720 throw new Error('Expected to find the previous sibling.');1721 }1722 }1723 prevSibling.sibling = newWorkInProgress;1724 } // Delete the old fiber and place the new one.1725 // Since the old fiber is disconnected, we have to schedule it manually.1726 var last = returnFiber.lastEffect;1727 if (last !== null) {1728 last.nextEffect = current;1729 returnFiber.lastEffect = current;1730 } else {1731 returnFiber.firstEffect = returnFiber.lastEffect = current;1732 }1733 current.nextEffect = null;1734 current.flags = Deletion;1735 newWorkInProgress.flags |= Placement; // Restart work from the new fiber.1736 return newWorkInProgress;1737 }1738 }1739 function beginWork(current, workInProgress, renderLanes) {1740 var updateLanes = workInProgress.lanes;1741 {1742 if (workInProgress._debugNeedsRemount && current !== null) {1743 // This will restart the begin phase with a new fiber.1744 return remountFiber(current, workInProgress, createFiberFromTypeAndProps(workInProgress.type, workInProgress.key, workInProgress.pendingProps, workInProgress._debugOwner || null, workInProgress.mode, workInProgress.lanes));1745 }1746 }1747 if (current !== null) {1748 var oldProps = current.memoizedProps;1749 var newProps = workInProgress.pendingProps;1750 if (oldProps !== newProps || hasContextChanged() || ( // Force a re-render if the implementation changed due to hot reload:1751 workInProgress.type !== current.type )) {1752 // If props or context changed, mark the fiber as having performed work.1753 // This may be unset if the props are determined to be equal later (memo).1754 didReceiveUpdate = true;1755 } else if (!includesSomeLane(renderLanes, updateLanes)) {1756 didReceiveUpdate = false; // This fiber does not have any pending work. Bailout without entering1757 // the begin phase. There's still some bookkeeping we that needs to be done1758 // in this optimized path, mostly pushing stuff onto the stack.1759 switch (workInProgress.tag) {1760 case HostRoot:1761 pushHostRootContext(workInProgress);1762 resetHydrationState();1763 break;1764 case HostComponent:1765 pushHostContext(workInProgress);1766 break;1767 case ClassComponent:1768 {1769 var Component = workInProgress.type;1770 if (isContextProvider(Component)) {1771 pushContextProvider(workInProgress);1772 }1773 break;1774 }1775 case HostPortal:1776 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);1777 break;1778 case ContextProvider:1779 {1780 var newValue = workInProgress.memoizedProps.value;1781 pushProvider(workInProgress, newValue);1782 break;1783 }1784 case Profiler:1785 {1786 // Profiler should only call onRender when one of its descendants actually rendered.1787 var hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes);1788 if (hasChildWork) {1789 workInProgress.flags |= Update;1790 } // Reset effect durations for the next eventual effect phase.1791 // These are reset during render to allow the DevTools commit hook a chance to read them,1792 var stateNode = workInProgress.stateNode;1793 stateNode.effectDuration = 0;1794 stateNode.passiveEffectDuration = 0;1795 }1796 break;1797 case SuspenseComponent:1798 {1799 var state = workInProgress.memoizedState;1800 if (state !== null) {1801 {1802 if (state.dehydrated !== null) {1803 pushSuspenseContext(workInProgress, setDefaultShallowSuspenseContext(suspenseStackCursor.current)); // We know that this component will suspend again because if it has1804 // been unsuspended it has committed as a resolved Suspense component.1805 // If it needs to be retried, it should have work scheduled on it.1806 workInProgress.flags |= DidCapture; // We should never render the children of a dehydrated boundary until we1807 // upgrade it. We return null instead of bailoutOnAlreadyFinishedWork.1808 return null;1809 }1810 } // If this boundary is currently timed out, we need to decide1811 // whether to retry the primary children, or to skip over it and1812 // go straight to the fallback. Check the priority of the primary1813 // child fragment.1814 var primaryChildFragment = workInProgress.child;1815 var primaryChildLanes = primaryChildFragment.childLanes;1816 if (includesSomeLane(renderLanes, primaryChildLanes)) {1817 // The primary children have pending work. Use the normal path1818 // to attempt to render the primary children again.1819 return updateSuspenseComponent(current, workInProgress, renderLanes);1820 } else {1821 // The primary child fragment does not have pending work marked1822 // on it1823 pushSuspenseContext(workInProgress, setDefaultShallowSuspenseContext(suspenseStackCursor.current)); // The primary children do not have pending work with sufficient1824 // priority. Bailout.1825 var child = bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1826 if (child !== null) {1827 // The fallback children have pending work. Skip over the1828 // primary children and work on the fallback.1829 return child.sibling;1830 } else {1831 return null;1832 }1833 }1834 } else {1835 pushSuspenseContext(workInProgress, setDefaultShallowSuspenseContext(suspenseStackCursor.current));1836 }1837 break;1838 }1839 case SuspenseListComponent:1840 {1841 var didSuspendBefore = (current.flags & DidCapture) !== NoFlags;1842 var _hasChildWork = includesSomeLane(renderLanes, workInProgress.childLanes);1843 if (didSuspendBefore) {1844 if (_hasChildWork) {1845 // If something was in fallback state last time, and we have all the1846 // same children then we're still in progressive loading state.1847 // Something might get unblocked by state updates or retries in the1848 // tree which will affect the tail. So we need to use the normal1849 // path to compute the correct tail.1850 return updateSuspenseListComponent(current, workInProgress, renderLanes);1851 } // If none of the children had any work, that means that none of1852 // them got retried so they'll still be blocked in the same way1853 // as before. We can fast bail out.1854 workInProgress.flags |= DidCapture;1855 } // If nothing suspended before and we're rendering the same children,1856 // then the tail doesn't matter. Anything new that suspends will work1857 // in the "together" mode, so we can continue from the state we had.1858 var renderState = workInProgress.memoizedState;1859 if (renderState !== null) {1860 // Reset to the "together" mode in case we've started a different1861 // update in the past but didn't complete it.1862 renderState.rendering = null;1863 renderState.tail = null;1864 renderState.lastEffect = null;1865 }1866 pushSuspenseContext(workInProgress, suspenseStackCursor.current);1867 if (_hasChildWork) {1868 break;1869 } else {1870 // If none of the children had any work, that means that none of1871 // them got retried so they'll still be blocked in the same way1872 // as before. We can fast bail out.1873 return null;1874 }1875 }1876 case OffscreenComponent:1877 case LegacyHiddenComponent:1878 {1879 // Need to check if the tree still needs to be deferred. This is1880 // almost identical to the logic used in the normal update path,1881 // so we'll just enter that. The only difference is we'll bail out1882 // at the next level instead of this one, because the child props1883 // have not changed. Which is fine.1884 // TODO: Probably should refactor `beginWork` to split the bailout1885 // path from the normal path. I'm tempted to do a labeled break here1886 // but I won't :)1887 workInProgress.lanes = NoLanes;1888 return updateOffscreenComponent(current, workInProgress, renderLanes);1889 }1890 }1891 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);1892 } else {1893 if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {1894 // This is a special case that only exists for legacy mode.1895 // See https://github.com/facebook/react/pull/19216.1896 didReceiveUpdate = true;1897 } else {1898 // An update was scheduled on this fiber, but there are no new props1899 // nor legacy context. Set this to false. If an update queue or context1900 // consumer produces a changed value, it will set this to true. Otherwise,1901 // the component will assume the children have not changed and bail out.1902 didReceiveUpdate = false;1903 }1904 }1905 } else {1906 didReceiveUpdate = false;1907 } // Before entering the begin phase, clear pending update priority.1908 // TODO: This assumes that we're about to evaluate the component and process1909 // the update queue. However, there's an exception: SimpleMemoComponent1910 // sometimes bails out later in the begin phase. This indicates that we should1911 // move this assignment out of the common path and into each branch.1912 workInProgress.lanes = NoLanes;1913 switch (workInProgress.tag) {1914 case IndeterminateComponent:1915 {1916 return mountIndeterminateComponent(current, workInProgress, workInProgress.type, renderLanes);1917 }1918 case LazyComponent:1919 {1920 var elementType = workInProgress.elementType;1921 return mountLazyComponent(current, workInProgress, elementType, updateLanes, renderLanes);1922 }1923 case FunctionComponent:1924 {1925 var _Component = workInProgress.type;1926 var unresolvedProps = workInProgress.pendingProps;1927 var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps);1928 return updateFunctionComponent(current, workInProgress, _Component, resolvedProps, renderLanes);1929 }1930 case ClassComponent:1931 {1932 var _Component2 = workInProgress.type;1933 var _unresolvedProps = workInProgress.pendingProps;1934 var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps);1935 return updateClassComponent(current, workInProgress, _Component2, _resolvedProps, renderLanes);1936 }1937 case HostRoot:1938 return updateHostRoot(current, workInProgress, renderLanes);1939 case HostComponent:1940 return updateHostComponent(current, workInProgress, renderLanes);1941 case HostText:1942 return updateHostText(current, workInProgress);1943 case SuspenseComponent:1944 return updateSuspenseComponent(current, workInProgress, renderLanes);1945 case HostPortal:1946 return updatePortalComponent(current, workInProgress, renderLanes);1947 case ForwardRef:1948 {1949 var type = workInProgress.type;1950 var _unresolvedProps2 = workInProgress.pendingProps;1951 var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);1952 return updateForwardRef(current, workInProgress, type, _resolvedProps2, renderLanes);1953 }1954 case Fragment:1955 return updateFragment(current, workInProgress, renderLanes);1956 case Mode:1957 return updateMode(current, workInProgress, renderLanes);1958 case Profiler:1959 return updateProfiler(current, workInProgress, renderLanes);1960 case ContextProvider:1961 return updateContextProvider(current, workInProgress, renderLanes);1962 case ContextConsumer:1963 return updateContextConsumer(current, workInProgress, renderLanes);1964 case MemoComponent:1965 {1966 var _type2 = workInProgress.type;1967 var _unresolvedProps3 = workInProgress.pendingProps; // Resolve outer props first, then resolve inner props.1968 var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3);1969 {1970 if (workInProgress.type !== workInProgress.elementType) {1971 var outerPropTypes = _type2.propTypes;1972 if (outerPropTypes) {1973 checkPropTypes(outerPropTypes, _resolvedProps3, // Resolved for outer only1974 'prop', getComponentName(_type2));1975 }1976 }1977 }1978 _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3);1979 return updateMemoComponent(current, workInProgress, _type2, _resolvedProps3, updateLanes, renderLanes);1980 }1981 case SimpleMemoComponent:1982 {1983 return updateSimpleMemoComponent(current, workInProgress, workInProgress.type, workInProgress.pendingProps, updateLanes, renderLanes);1984 }1985 case IncompleteClassComponent:1986 {1987 var _Component3 = workInProgress.type;1988 var _unresolvedProps4 = workInProgress.pendingProps;1989 var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4);1990 return mountIncompleteClassComponent(current, workInProgress, _Component3, _resolvedProps4, renderLanes);1991 }1992 case SuspenseListComponent:1993 {1994 return updateSuspenseListComponent(current, workInProgress, renderLanes);1995 }1996 case FundamentalComponent:1997 {1998 break;1999 }2000 case ScopeComponent:2001 {2002 break;2003 }2004 case Block:2005 {2006 {2007 var block = workInProgress.type;2008 var props = workInProgress.pendingProps;2009 return updateBlock(current, workInProgress, block, props, renderLanes);2010 }2011 }2012 case OffscreenComponent:2013 {2014 return updateOffscreenComponent(current, workInProgress, renderLanes);2015 }2016 case LegacyHiddenComponent:2017 {2018 return updateLegacyHiddenComponent(current, workInProgress, renderLanes);2019 }2020 }2021 {2022 {2023 throw Error( "Unknown unit of work tag (" + workInProgress.tag + "). This error is likely caused by a bug in React. Please file an issue." );2024 }2025 }...
ReactFiberBeginWork.js
Source:ReactFiberBeginWork.js
...213 // TODO: Probably should refactor `beginWork` to split the bailout214 // path from the normal path. I'm tempted to do a labeled break here215 // but I won't :)216 workInProgress.lanes = NoLanes;217 return updateOffscreenComponent(current, workInProgress, renderLanes);218 }219 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);220 } else {221 // flagsæ è¯å¯ä½ç¨222 // é¦æ¬¡æ¸²æcurrent.flagsåºè¯¥æ¯ NoFlags = 0223 if ((current.flags & ForceUpdateForLegacySuspense) !== NoFlags) {224 // æä½ä¸è¿ç®ç»æä¸ä¸º0ï¼ ä¹å°±æ¯è¯´current.flagsè¯å®å
å«ForceUpdateForLegacySuspense225 // This is a special case that only exists for legacy mode.226 // See https://github.com/facebook/react/pull/19216.227 didReceiveUpdate = true;228 } else {229 // å次渲æèµ°è¿æ¡230 // An update was scheduled on this fiber, but there are no new props231 // nor legacy context. Set this to false. If an update queue or context232 // consumer produces a changed value, it will set this to true. Otherwise,233 // the component will assume the children have not changed and bail out.234 didReceiveUpdate = false;235 }236 }237 } else {238 didReceiveUpdate = false;239 }240 // Before entering the begin phase, clear pending update priority.241 // TODO: This assumes that we're about to evaluate the component and process242 // the update queue. However, there's an exception: SimpleMemoComponent243 // sometimes bails out later in the begin phase. This indicates that we should244 // move this assignment out of the common path and into each branch.245 // ææ¶ä¸æç½ä¸ºä½è¦æ¸
é¤WIPçlanes246 workInProgress.lanes = NoLanes;247 // å次渲æï¼ ç¬¬ä¸æ¬¡loopï¼ è¿éçwipåºè¯¥æ¯ host fiber root, tag 为 HostRoot = 3248 // å次渲æï¼ ç¬¬äºæ¬¡loopï¼ è¿éçwipåºè¯¥æ¯ 项ç®åºç¨æ ¹èç¹ï¼ å¨æå¦ä¹ çååä¸ä¸º<App>, tag 为 IndeterminateComponent = 2249 switch (workInProgress.tag) {250 case IndeterminateComponent: {251 // æç»è¿åçæ¯<App>ä¸ç第ä¸ä¸ªchildèç¹, ä¸ä¸ªHTMLDivELementèç¹252 return mountIndeterminateComponent(253 current,254 workInProgress,255 workInProgress.type,256 renderLanes257 );258 }259 case LazyComponent: {260 const elementType = workInProgress.elementType;261 return mountLazyComponent(262 current,263 workInProgress,264 elementType,265 updateLanes,266 renderLanes267 );268 }269 case FunctionComponent: {270 const Component = workInProgress.type;271 const unresolvedProps = workInProgress.pendingProps;272 const resolvedProps =273 workInProgress.elementType === Component274 ? unresolvedProps275 : resolveDefaultProps(Component, unresolvedProps);276 return updateFunctionComponent(277 current,278 workInProgress,279 Component,280 resolvedProps,281 renderLanes282 );283 }284 case ClassComponent: {285 const Component = workInProgress.type;286 const unresolvedProps = workInProgress.pendingProps;287 const resolvedProps =288 workInProgress.elementType === Component289 ? unresolvedProps290 : resolveDefaultProps(Component, unresolvedProps);291 return updateClassComponent(292 current,293 workInProgress,294 Component,295 resolvedProps,296 renderLanes297 );298 }299 case HostRoot:300 return updateHostRoot(current, workInProgress, renderLanes);301 case HostComponent:302 return updateHostComponent(current, workInProgress, renderLanes);303 case HostText:304 return updateHostText(current, workInProgress);305 case SuspenseComponent:306 return updateSuspenseComponent(current, workInProgress, renderLanes);307 case HostPortal:308 return updatePortalComponent(current, workInProgress, renderLanes);309 case ForwardRef: {310 const type = workInProgress.type;311 const unresolvedProps = workInProgress.pendingProps;312 const resolvedProps =313 workInProgress.elementType === type314 ? unresolvedProps315 : resolveDefaultProps(type, unresolvedProps);316 return updateForwardRef(317 current,318 workInProgress,319 type,320 resolvedProps,321 renderLanes322 );323 }324 case Fragment:325 return updateFragment(current, workInProgress, renderLanes);326 case Mode:327 return updateMode(current, workInProgress, renderLanes);328 case Profiler:329 return updateProfiler(current, workInProgress, renderLanes);330 case ContextProvider:331 return updateContextProvider(current, workInProgress, renderLanes);332 case ContextConsumer:333 return updateContextConsumer(current, workInProgress, renderLanes);334 case MemoComponent: {335 const type = workInProgress.type;336 const unresolvedProps = workInProgress.pendingProps;337 // Resolve outer props first, then resolve inner props.338 let resolvedProps = resolveDefaultProps(type, unresolvedProps);339 resolvedProps = resolveDefaultProps(type.type, resolvedProps);340 return updateMemoComponent(341 current,342 workInProgress,343 type,344 resolvedProps,345 updateLanes,346 renderLanes347 );348 }349 case SimpleMemoComponent: {350 return updateSimpleMemoComponent(351 current,352 workInProgress,353 workInProgress.type,354 workInProgress.pendingProps,355 updateLanes,356 renderLanes357 );358 }359 case IncompleteClassComponent: {360 const Component = workInProgress.type;361 const unresolvedProps = workInProgress.pendingProps;362 const resolvedProps =363 workInProgress.elementType === Component364 ? unresolvedProps365 : resolveDefaultProps(Component, unresolvedProps);366 return mountIncompleteClassComponent(367 current,368 workInProgress,369 Component,370 resolvedProps,371 renderLanes372 );373 }374 case SuspenseListComponent: {375 return updateSuspenseListComponent(current, workInProgress, renderLanes);376 }377 case FundamentalComponent: {378 if (enableFundamentalAPI) {379 return updateFundamentalComponent(current, workInProgress, renderLanes);380 }381 break;382 }383 case ScopeComponent: {384 if (enableScopeAPI) {385 return updateScopeComponent(current, workInProgress, renderLanes);386 }387 break;388 }389 case Block: {390 if (enableBlocksAPI) {391 const block = workInProgress.type;392 const props = workInProgress.pendingProps;393 return updateBlock(current, workInProgress, block, props, renderLanes);394 }395 break;396 }397 case OffscreenComponent: {398 return updateOffscreenComponent(current, workInProgress, renderLanes);399 }400 case LegacyHiddenComponent: {401 return updateLegacyHiddenComponent(current, workInProgress, renderLanes);402 }403 }404 invariant(405 false,406 "Unknown unit of work tag (%s). This error is likely caused by a bug in " +407 "React. Please file an issue.",408 workInProgress.tag409 );410}411function pushHostRootContext(workInProgress) {412 const root = workInProgress.stateNode;...
FiberBeginWork.js
Source:FiberBeginWork.js
...55} from '@Jeact/vDOM/FiberWorkLoop';56import {createElement} from '@Jeact/Element';57let didReceiveUpdate = false;58const defaultFallbackChildren=createElement('p',{'className':'fallback'},'Loading...');59function updateOffscreenComponent(60 current,61 workInProgress,62 renderLanes63){64 const nextProps = workInProgress.pendingProps;65 const nextChildren = nextProps.children;66 const prevState = current !== null ? current.memoizedState : null;67 if (nextProps.mode === 'hidden'){68 debugger;69 } else {70 // Rendering a visible tree.71 let subtreeRenderLanes;72 if (prevState !== null){73 // toggle hidden tree to visible.74 subtreeRenderLanes = mergeLanes(prevState.baseLanes, renderLanes);75 // Not hidden anymore.76 workInProgress.memoizedState = null;77 } else{78 subtreeRenderLanes = renderLanes;79 }80 pushRenderLanes(workInProgress, subtreeRenderLanes);81 }82 // reconcileChildren()83 workInProgress.child = reconcileChildFibers(84 workInProgress,85 current,86 nextChildren,87 renderLanes88 );89 return workInProgress.child;90}91function updateFunctionComponent(current,workInProgress,renderLanes){92 let nextChildren = renderWithHooks(93 current,94 workInProgress,95 renderLanes,96 );97 if(current!==null && !didReceiveUpdate){98 // when passing the same value to Hooks, no need to reconcile and instead 99 // do a bailout.100 bailoutHooks(current, workInProgress, renderLanes);101 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);102 }103 workInProgress.child = reconcileChildFibers(104 workInProgress,105 current,106 nextChildren,107 renderLanes108 );109 return workInProgress.child;110}111function updateHostRoot(current, workInProgress, renderLanes){112 // push host container like div#root into stack, so we can get it to refer in 113 // any depth when we are reconcile fiber children.114 pushHostContainer(workInProgress);//pushHostRootContext()115 cloneUpdateQueue(current, workInProgress);116 processUpdateQueue(workInProgress, renderLanes);117 // updated from getStateFromUpdate() in processUpdateQueue();118 const nextState = workInProgress.memoizedState;119 const root = workInProgress.stateNode;120 const nextChildren = nextState.element;121 workInProgress.child = reconcileChildFibers(122 workInProgress,123 current,124 nextChildren,125 renderLanes126 );127 return workInProgress.child;128}129function updateHostComponent(current, workInProgress,renderLanes){130 const type = workInProgress.type;131 const nextProps = workInProgress.pendingProps;132 const prevProps = current !== null ? current.memoizedProps : null;133 let nextChildren = nextProps.children;134 const isDirectTextChild = shouldSetTextContent(nextProps);135 if (isDirectTextChild){136 // Handle direct text node in host environment to avoid another traversing.137 nextChildren = null;138 } else if (prevProps !== null && shouldSetTextContent(prevProps)){139 // switching from a direct text child to a normal child, or to empty.140 console.error('Need to test');141 workInProgress.flags |= ContentReset;142 }143 workInProgress.child = reconcileChildFibers(144 workInProgress,145 current,146 nextChildren,147 renderLanes,148 );149 return workInProgress.child;150}151function mountLazyComponent(workInProgress,renderLanes){152 const props = workInProgress.pendingProps;153 const lazyComponent = workInProgress.type;154 const payload = lazyComponent._payload;155 const init = lazyComponent._init;156 let Component = init(payload);157 158 workInProgress.type = Component;159 workInProgress.tag = FunctionComponent;160 return updateFunctionComponent(161 null,162 workInProgress,163 renderLanes164 )165}166const SUSPENDED_MARKER = {167 retryLane: NoLanes,168}169function mountSuspenseOffscreenState(renderLanes){170 return {171 baseLanes: renderLanes172 }173}174function updateSuspenseOffscreenState(175 prevOffscreenState,176 renderLanes,177){178 return {179 baseLanes: mergeLanes(prevOffscreenState.baseLanes, renderLanes),180 }181}182function shouldRemainOnFallback(suspenseContext, current, workInProgress){183 // If we're already showing a fallback, there are cases where we need to 184 // remain on that fallback regardless of whether the content has resolved.185 // e.g Suspense has unresolved children. 186 if (current !== null){187 const suspenseState = current.memoizedState;188 if(suspenseState === null){189 return false;190 }191 }192 // Not currently showing content. Consult the Suspense context.193 return hasSuspenseContext(194 suspenseContext,195 ForceSuspenseFallback196 )197}198function updateSuspenseComponent(current, workInProgress, renderLanes){ 199 const nextProps = workInProgress.pendingProps;200 let suspenseContext = suspenseStackCursor.current;201 let showFallback = false;202 const didSuspend = (workInProgress.flags & DidCapture) !== NoFlags;203 if(204 didSuspend ||205 shouldRemainOnFallback(206 suspenseContext,207 current,208 workInProgress209 )210 ){211 // part of the subtree has suspended and render the fallback children.212 showFallback = true;213 workInProgress.flags &= ~DidCapture;214 } else {215 // Attempting the main content216 if(217 current === null ||218 (current.memoizedState !== null)219 ){220 // This is a new mount waiting for resolving content or this boundary is 221 // already showing a fallback state.222 // Mark this subtree context as having at least one invisible parent that 223 // could handle the fallback state..224 suspenseContext = addSubtreeSuspenseContext(225 suspenseContext,226 InvisibleParentSuspenseContext,227 ) 228 }229 }230 // pushSuspenseContext()231 push(suspenseStackCursor, suspenseContext);232 if (current === null){233 // Initial mount234 const nextPrimaryChildren = nextProps.children;235 const nextFallbackChildren = nextProps.fallback;236 if (showFallback){237 const fallbackFragment = mountSuspenseFallbackChildren(238 workInProgress,239 nextPrimaryChildren,240 nextFallbackChildren,241 renderLanes,242 );243 const primaryChildFragment = workInProgress.child;244 primaryChildFragment.memoizedState = mountSuspenseOffscreenState(245 renderLanes,246 );247 workInProgress.memoizedState = SUSPENDED_MARKER;248 return fallbackFragment;249 } else {250 return mountSuspensePrimaryChildren(251 workInProgress,252 nextPrimaryChildren,253 renderLanes,254 )255 }256 } else {257 // Update.258 // If the current fiber has a SuspenseState, that means it's already 259 // showing a fallback.260 const prevState = current.memoizedState;261 if (prevState !== null){262 if (showFallback){263 const nextFallbackChildren = nextProps.fallback;264 const nextPrimaryChildren = nextProps.children;265 const fallbackChildFragment = updateSuspenseFallbackChildren(266 current,267 workInProgress,268 nextPrimaryChildren,269 nextFallbackChildren,270 renderLanes271 )272 const primaryChildFragment = workInProgress.child;273 const prevOffscreenState = current.child.memoizedState;274 primaryChildFragment.memoizedState = 275 prevOffscreenState === null276 ? mountSuspenseOffscreenState(renderLanes)277 : updateSuspenseOffscreenState(prevOffscreenState, renderLanes); 278 primaryChildFragment.childLanes = removeLanes(279 current.childLanes, 280 renderLanes281 );282 workInProgress.memoizedState = SUSPENDED_MARKER;283 return fallbackChildFragment; 284 } else {285 const nextPrimaryChildren = nextProps.children;286 const primaryChildFragment = updateSuspensePrimaryChildren(287 current,288 workInProgress,289 nextPrimaryChildren,290 renderLanes,291 );292 workInProgress.memoizedState = null;293 return primaryChildFragment;294 }295 } else {296 // the current tree is not showing a fallback.297 if(showFallback){298 // Timed out.299 const nextFallbackChildren = nextProps.fallback;300 const nextPrimaryChildren = nextProps.children;301 const fallbackChildFragment = updateSuspenseFallbackChildren(302 current,303 workInProgress,304 nextPrimaryChildren,305 nextFallbackChildren,306 renderLanes307 )308 const primaryChildFragment = workInProgress.child;309 const prevOffscreenState = current.child.memoizedState;310 primaryChildFragment.memoizedState = 311 prevOffscreenState === null312 ? mountSuspenseOffscreenState(renderLanes)313 : updateSuspenseOffscreenState(prevOffscreenState, renderLanes); 314 primaryChildFragment.childLanes = removeLanes(315 current.childLanes, 316 renderLanes317 );318 workInProgress.memoizedState = SUSPENDED_MARKER;319 return fallbackChildFragment;320 } else {321 const nextPrimaryChildren = nextProps.children;322 const primaryChildFragment = updateSuspensePrimaryChildren(323 current,324 workInProgress,325 nextPrimaryChildren,326 renderLanes,327 );328 workInProgress.memoizedState = null;329 return primaryChildFragment;330 }331 }332 }333}334function mountSuspensePrimaryChildren(335 workInProgress,336 primaryChildren,337 renderLanes338){339 const primaryChildProps = {340 mode: 'visible',341 children: primaryChildren,342 };343 // createFiberFromOffscreen()344 const primaryChildFragment = createFiber(345 OffscreenComponent,346 primaryChildProps347 );348 primaryChildFragment.elementType = JEACT_OFFSCREEN_TYPE;349 primaryChildFragment.lanes = renderLanes;350 primaryChildFragment.return = workInProgress;351 workInProgress.child = primaryChildFragment;352 return primaryChildFragment;353}354function mountSuspenseFallbackChildren(355 workInProgress,356 primaryChildren,357 fallbackChildren=defaultFallbackChildren,358 renderLanes,359){360 if(typeof fallbackChildren === 'string'){361 console.error('Err:Fallback Component should be an Object, got String:', fallbackChildren)362 }363 const primaryChildProps = {364 mode: 'hidden',365 children: primaryChildren,366 };367 let primaryChildFragment;368 let fallbackChildFragment;369 primaryChildFragment = createFiber(370 OffscreenComponent,371 primaryChildProps,372 null,373 );374 primaryChildFragment.elementType = JEACT_OFFSCREEN_TYPE;375 primaryChildFragment.lanes = NoLanes;376 fallbackChildFragment = reconcileChildFibers(377 workInProgress,378 null,379 fallbackChildren,380 renderLanes381 );382 fallbackChildFragment.lanes = renderLanes;383 fallbackChildFragment.elementType = JEACT_FALLBACK_TYPE;384 primaryChildFragment.return = workInProgress;385 fallbackChildFragment.return = workInProgress;386 primaryChildFragment.sibling = fallbackChildFragment;387 workInProgress.child = primaryChildFragment;388 return fallbackChildFragment;389}390function updateSuspensePrimaryChildren(391 current,392 workInProgress,393 primaryChildren,394 renderLanes395){396 const currentPrimaryChildFragment = current.child;397 const currentFallbackChildFragment = currentPrimaryChildFragment.sibling;398 // createWorkInProgressOffscreenFiber()399 const primaryChildFragment = createWorkInProgress(400 currentPrimaryChildFragment,401 {402 mode: 'visible',403 children: primaryChildren,404 }405 )406 primaryChildFragment.return = workInProgress;407 primaryChildFragment.sibling = null;408 if (currentFallbackChildFragment !== null){409 // Delete the fallback child fragment410 const deletions = workInProgress.deletions;411 if (deletions === null){412 workInProgress.deletions = [currentFallbackChildFragment];413 workInProgress.flags |= ChildDeletion;414 } else {415 deletions.push(currentFallbackChildFragment);416 }417 }418 workInProgress.child = primaryChildFragment;419 return primaryChildFragment;420}421function updateSuspenseFallbackChildren(422 current,423 workInProgress,424 primaryChildren,425 fallbackChildren=defaultFallbackChildren,426 renderLanes,427){428 const currentPrimaryChildFragment = current.child;429 const currentFallbackChildFragment = currentPrimaryChildFragment.sibling;430 const primaryChildProps = {431 mode:'hidden',432 children: primaryChildren,433 };434 let primaryChildFragment = createWorkInProgress(435 currentPrimaryChildFragment,436 primaryChildProps,437 );438 primaryChildFragment.subtreeFlags = 439 currentPrimaryChildFragment.subtreeFlags & StaticMask;440 let fallbackChildFragment;441 if(currentFallbackChildFragment !== null){442 fallbackChildFragment = createWorkInProgress(443 currentFallbackChildFragment,444 fallbackChildren,445 );446 } else {447 fallbackChildFragment = reconcileChildFibers(448 workInProgress,449 null,450 fallbackChildren,451 renderLanes,452 );453 fallbackChildFragment.flags |= Placement;454 }455 fallbackChildFragment.lanes = renderLanes;456 fallbackChildFragment.elementType = JEACT_FALLBACK_TYPE;457 458 fallbackChildFragment.return = workInProgress;459 primaryChildFragment.return = workInProgress;460 primaryChildFragment.sibling = fallbackChildFragment;461 workInProgress.child = primaryChildFragment;462 463 return fallbackChildFragment;464}465function checkScheduledUpdateOrContext(current,renderLanes){466 const updateLanes = current.lanes;467 if(includesSomeLane(updateLanes, renderLanes)){468 return true;469 }470 return false;471}472function bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes){473 markSkippedUpdateLanes(workInProgress.lanes);474 // Check if the children have any pending work.475 if (!includesSomeLane(renderLanes, workInProgress.childLanes)){476 // The children don't have any work either.477 return null;478 } 479 // This fiber doesn't have work, but its subtree does. Clone the child 480 // fibers and continue. And RootFiber always clones its ChildFibers 481 // here.482 cloneChildFibers(current, workInProgress);483 return workInProgress.child;484}485function attemptEarlyBailoutIfNoScheduledUpdate(486 current,487 workInProgress,488 renderLanes,489){490 switch(workInProgress.tag){491 case HostRoot:{492 pushHostContainer(workInProgress);493 break;494 }495 }496 return bailoutOnAlreadyFinishedWork(current, workInProgress, renderLanes);497}498// Iterate from parent fibers to child fibers(including sibling fibers) to build the whole fiber tree.499export function beginWork(current, workInProgress, renderLanes){500 const updateLanes = workInProgress.lanes;501 if(current!==null){502 // Update phase503 const oldProps = current.memoizedProps;504 const newProps = workInProgress.pendingProps;505 if(oldProps !== newProps){506 didReceiveUpdate = true;507 } else {508 const hasScheduledUpdateOrContext = checkScheduledUpdateOrContext(509 current,510 renderLanes,511 );512 if(513 !hasScheduledUpdateOrContext &&514 (workInProgress.flags & DidCapture) === NoFlags515 ){516 didReceiveUpdate = false;517 return attemptEarlyBailoutIfNoScheduledUpdate(518 current,519 workInProgress,520 renderLanes,521 );522 }523 524 }525 } else {526 didReceiveUpdate = false;527 }528 // prevent lanes from passing to fiber.lanes of HostComponent's child fibers, and further to childLanes in bubbleProperties().529 workInProgress.lanes = NoLanes;530 switch (workInProgress.tag){531 case HostRoot://0532 return updateHostRoot(current, workInProgress, renderLanes);533 case FunctionComponent://1534 return updateFunctionComponent(current,workInProgress,renderLanes);535 case HostComponent://2536 return updateHostComponent(current, workInProgress, renderLanes);537 case HostText://3538 return null;539 case SuspenseComponent://4540 return updateSuspenseComponent(current, workInProgress, renderLanes);541 case OffscreenComponent://5542 return updateOffscreenComponent(current, workInProgress, renderLanes);543 case LazyComponent:{544 return mountLazyComponent(545 workInProgress,546 renderLanes547 );548 }549 }550}551export function markWorkInProgressReceivedUpdate(){552 didReceiveUpdate = true;...
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const page = await browser.newPage();5 await page.waitForSelector('text=Learn');6 const element = await page.$('text=Learn');7 await element.evaluate(element => {8 window.playwright._internal.updateOffscreenComponent(element, {9 transform: 'rotate(45deg)',10 });11 });12 await page.screenshot({ path: 'screenshot.png' });13 await browser.close();14})();15{16 "scripts": {17 },18 "dependencies": {19 }20}
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const page = await browser.newPage();5 const offscreenComponent = await page.updateOffscreenComponent();6 const html = await offscreenComponent.innerHTML();7 console.log(html);8 await browser.close();9})();10The updateOffscreenComponent method of Playwright Internal API is used to get the inner HTML of the page. The method returns a promise that resolves to an object with the following methods: innerHTML() - Returns a promise that resolves to a string with the HTML of the page. innerText() - Returns a promise that resolves to a string with the text content of the page. textContent() - Returns a promise that resolves to a string with the text content of the page. title() -
Using AI Code Generation
1const { updateOffscreenComponent } = require('playwright');2const path = require('path');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 const component = await updateOffscreenComponent(page, {8 path: path.join(__dirname, 'my-component.js'),9 attributes: {10 },11 properties: {12 },13 styles: {14 },15 });16 await page.setContent(component.html);17 await page.screenshot({ path: 'example.png' });18 await browser.close();19})();20class MyComponent extends HTMLElement {21 static get observedAttributes() {22 return ['my-attribute'];23 }24 constructor() {25 super();26 this.attachShadow({ mode: 'open' });27 }28 attributeChangedCallback(name, oldValue, newValue) {29 <p>Old value: ${oldValue}</p>30 <p>New value: ${newValue}</p>31 `;32 }33 connectedCallback() {34 <h1>my-attribute: ${this.getAttribute('my-attribute')}</h1>35 <p>myProperty: ${this.myProperty}</p>36 `;37 }38 set myProperty(value) {39 this._myProperty = value;40 this.shadowRoot.querySelector('p').innerText = `myProperty: ${value}`;41 }42 get myProperty() {43 return this._myProperty;44 }45}46customElements.define('my-component', MyComponent);47const { updateOffscreenComponent } = require('playwright');48const path = require('path');49(async () => {50 const browser = await chromium.launch();51 const context = await browser.newContext();52 const page = await context.newPage();
Using AI Code Generation
1const { chromium } = require('playwright');2(async () => {3 const browser = await chromium.launch();4 const context = await browser.newContext();5 const page = await context.newPage();6 const offscreenContext = await browser.newContext({7 });8 const offscreenPage = await offscreenContext.newPage();9 await page.evaluate(async () => {10 await window.__playwright__updateOffscreenComponent();11 });12 await offscreenPage.screenshot({ path: 'example.png' });13 await browser.close();14})();15{16 "dependencies": {17 }18}19const { chromium } = require('playwright');20(async () => {21 await chromium._downloadBrowserWithProgressBar();22})();23const { chromium } = require('playwright');24(async () => {25 await chromium._downloadBrowserWithProgressBar();26})();
Using AI Code Generation
1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch();4 const page = await browser.newPage();5 await page.setContent('<div>Test</div>');6 const div = await page.$('div');7 await page.evaluate(div => div.textContent = 'Hello', div);8 await browser.close();9})();10const playwright = require('playwright');11(async () => {12 const browser = await playwright.chromium.launch();13 const page = await browser.newPage();14 await page.setContent('<input type="text" />');15 const input = await page.$('input');16 await page.evaluate(input => input.value = 'Hello', input);17 await browser.close();18})();19const playwright = require('playwright');20(async () => {21 const browser = await playwright.chromium.launch();22 const page = await browser.newPage();23 await page.setContent('<img />');24 const img = await page.$('img');25 await browser.close();26})();
Using AI Code Generation
1const { updateOffscreenComponent } = require('playwright/lib/server/frames');2const { Frame } = require('playwright/lib/server/frame');3const { assert } = require('console');4const frame = new Frame();5const html = `<div id="test" style="width: 100px; height: 100px; background-color: red;"></div>`;6frame.updateOffscreenComponent(html, 'div#test', {7});8assert(frame._offscreenComponent);9const { updateOffscreenComponent } = require('playwright/lib/server/frames');10const { Frame } = require('playwright/lib/server/frame');11const { assert } = require('console');12const frame = new Frame();13const html = `<div id="test" style="width: 100px; height: 100px; background-color: red;"></div>`;14frame.updateOffscreenComponent(html, 'div#test', {15});16assert(frame._offscreenComponent);17const { updateOffscreenComponent } = require('playwright/lib/server/frames');18const { Frame } = require('playwright/lib/server/frame');19const { assert } = require('console');20const frame = new Frame();21const html = `<div id="test" style="width: 100px; height: 100px; background-color: red;"></div>`;22frame.updateOffscreenComponent(html, 'div#test', {23});24assert(frame._offscreenComponent);25const { updateOffscreenComponent } = require('playwright/lib/server/frames');26const { Frame } = require('playwright/lib/server/frame');27const { assert } = require('console');28const frame = new Frame();29const html = `<div id="test" style="width: 100px; height: 100px; background-color: red;"></div>`;30frame.updateOffscreenComponent(html, 'div#test', {
Using AI Code Generation
1const { _electron } = require('playwright');2const { updateOffscreenComponent } = _electron;3const { app, BrowserWindow } = require('electron');4async function createWindow() {5 const win = new BrowserWindow({6 webPreferences: {7 }8 });9 win.loadFile('index.html');10}11app.whenReady().then(async () => {12 await createWindow();13 await updateOffscreenComponent();14});
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!