How to use updateOffscreenComponent method in Playwright Internal

Best JavaScript code snippet using playwright-internal

ReactFiberBeginWork.new.js

Source:ReactFiberBeginWork.new.js Github

copy

Full Screen

...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}...

Full Screen

Full Screen

ReactFiberBeginWork.old.js

Source:ReactFiberBeginWork.old.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

ReactFiberBeginWork.js

Source:ReactFiberBeginWork.js Github

copy

Full Screen

...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;...

Full Screen

Full Screen

FiberBeginWork.js

Source:FiberBeginWork.js Github

copy

Full Screen

...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;...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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}

Full Screen

Using AI Code Generation

copy

Full Screen

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() -

Full Screen

Using AI Code Generation

copy

Full Screen

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();

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Using AI Code Generation

copy

Full Screen

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', {

Full Screen

Using AI Code Generation

copy

Full Screen

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});

Full Screen

Playwright tutorial

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.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful