Best JavaScript code snippet using playwright-internal
ReactFiberCommitWork.old.js
Source:ReactFiberCommitWork.old.js
...1346 }1347 fiber.return = null;1348}13491350function detachFiberAfterEffects(fiber: Fiber) {1351 const alternate = fiber.alternate;1352 if (alternate !== null) {1353 fiber.alternate = null;1354 detachFiberAfterEffects(alternate);1355 }13561357 // Note: Defensively using negation instead of < in case1358 // `deletedTreeCleanUpLevel` is undefined.1359 if (!(deletedTreeCleanUpLevel >= 2)) {1360 // This is the default branch (level 0).1361 fiber.child = null;1362 fiber.deletions = null;1363 fiber.dependencies = null;1364 fiber.memoizedProps = null;1365 fiber.memoizedState = null;1366 fiber.pendingProps = null;1367 fiber.sibling = null;1368 fiber.stateNode = null;1369 fiber.updateQueue = null;13701371 if (__DEV__) {1372 fiber._debugOwner = null;1373 }1374 } else {1375 // Clear cyclical Fiber fields. This level alone is designed to roughly1376 // approximate the planned Fiber refactor. In that world, `setState` will be1377 // bound to a special "instance" object instead of a Fiber. The Instance1378 // object will not have any of these fields. It will only be connected to1379 // the fiber tree via a single link at the root. So if this level alone is1380 // sufficient to fix memory issues, that bodes well for our plans.1381 fiber.child = null;1382 fiber.deletions = null;1383 fiber.sibling = null;13841385 // The `stateNode` is cyclical because on host nodes it points to the host1386 // tree, which has its own pointers to children, parents, and siblings.1387 // The other host nodes also point back to fibers, so we should detach that1388 // one, too.1389 if (fiber.tag === HostComponent) {1390 const hostInstance: Instance = fiber.stateNode;1391 if (hostInstance !== null) {1392 detachDeletedInstance(hostInstance);1393 }1394 }1395 fiber.stateNode = null;13961397 // I'm intentionally not clearing the `return` field in this level. We1398 // already disconnect the `return` pointer at the root of the deleted1399 // subtree (in `detachFiberMutation`). Besides, `return` by itself is not1400 // cyclical â it's only cyclical when combined with `child`, `sibling`, and1401 // `alternate`. But we'll clear it in the next level anyway, just in case.14021403 if (__DEV__) {1404 fiber._debugOwner = null;1405 }14061407 if (deletedTreeCleanUpLevel >= 3) {1408 // Theoretically, nothing in here should be necessary, because we already1409 // disconnected the fiber from the tree. So even if something leaks this1410 // particular fiber, it won't leak anything else1411 //1412 // The purpose of this branch is to be super aggressive so we can measure1413 // if there's any difference in memory impact. If there is, that could1414 // indicate a React leak we don't know about.1415 fiber.return = null;1416 fiber.dependencies = null;1417 fiber.memoizedProps = null;1418 fiber.memoizedState = null;1419 fiber.pendingProps = null;1420 fiber.stateNode = null;1421 // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead.1422 fiber.updateQueue = null;1423 }1424 }1425}14261427function emptyPortalContainer(current: Fiber) {1428 if (!supportsPersistence) {1429 return;1430 }14311432 const portal: {1433 containerInfo: Container,1434 pendingChildren: ChildSet,1435 ...1436 } = current.stateNode;1437 const {containerInfo} = portal;1438 const emptyChildSet = createContainerChildSet(containerInfo);1439 replaceContainerChildren(containerInfo, emptyChildSet);1440}14411442function commitContainer(finishedWork: Fiber) {1443 if (!supportsPersistence) {1444 return;1445 }14461447 switch (finishedWork.tag) {1448 case ClassComponent:1449 case HostComponent:1450 case HostText: {1451 return;1452 }1453 case HostRoot:1454 case HostPortal: {1455 const portalOrRoot: {1456 containerInfo: Container,1457 pendingChildren: ChildSet,1458 ...1459 } = finishedWork.stateNode;1460 const {containerInfo, pendingChildren} = portalOrRoot;1461 replaceContainerChildren(containerInfo, pendingChildren);1462 return;1463 }1464 }1465 invariant(1466 false,1467 'This unit of work tag should not have side-effects. This error is ' +1468 'likely caused by a bug in React. Please file an issue.',1469 );1470}14711472function getHostParentFiber(fiber: Fiber): Fiber {1473 let parent = fiber.return;1474 while (parent !== null) {1475 if (isHostParent(parent)) {1476 return parent;1477 }1478 parent = parent.return;1479 }1480 invariant(1481 false,1482 'Expected to find a host parent. This error is likely caused by a bug ' +1483 'in React. Please file an issue.',1484 );1485}14861487function isHostParent(fiber: Fiber): boolean {1488 return (1489 fiber.tag === HostComponent ||1490 fiber.tag === HostRoot ||1491 fiber.tag === HostPortal1492 );1493}14941495function getHostSibling(fiber: Fiber): ?Instance {1496 // We're going to search forward into the tree until we find a sibling host1497 // node. Unfortunately, if multiple insertions are done in a row we have to1498 // search past them. This leads to exponential search for the next sibling.1499 // TODO: Find a more efficient way to do this.1500 let node: Fiber = fiber;1501 siblings: while (true) {1502 // If we didn't find anything, let's try the next sibling.1503 while (node.sibling === null) {1504 if (node.return === null || isHostParent(node.return)) {1505 // If we pop out of the root or hit the parent the fiber we are the1506 // last sibling.1507 return null;1508 }1509 node = node.return;1510 }1511 node.sibling.return = node.return;1512 node = node.sibling;1513 while (1514 node.tag !== HostComponent &&1515 node.tag !== HostText &&1516 node.tag !== DehydratedFragment1517 ) {1518 // If it is not host node and, we might have a host node inside it.1519 // Try to search down until we find one.1520 if (node.flags & Placement) {1521 // If we don't have a child, try the siblings instead.1522 continue siblings;1523 }1524 // If we don't have a child, try the siblings instead.1525 // We also skip portals because they are not part of this host tree.1526 if (node.child === null || node.tag === HostPortal) {1527 continue siblings;1528 } else {1529 node.child.return = node;1530 node = node.child;1531 }1532 }1533 // Check if this host node is stable or about to be placed.1534 if (!(node.flags & Placement)) {1535 // Found it!1536 return node.stateNode;1537 }1538 }1539}15401541function commitPlacement(finishedWork: Fiber): void {1542 if (!supportsMutation) {1543 return;1544 }15451546 // Recursively insert all host nodes into the parent.1547 const parentFiber = getHostParentFiber(finishedWork);15481549 // Note: these two variables *must* always be updated together.1550 let parent;1551 let isContainer;1552 const parentStateNode = parentFiber.stateNode;1553 switch (parentFiber.tag) {1554 case HostComponent:1555 parent = parentStateNode;1556 isContainer = false;1557 break;1558 case HostRoot:1559 parent = parentStateNode.containerInfo;1560 isContainer = true;1561 break;1562 case HostPortal:1563 parent = parentStateNode.containerInfo;1564 isContainer = true;1565 break;1566 // eslint-disable-next-line-no-fallthrough1567 default:1568 invariant(1569 false,1570 'Invalid host parent fiber. This error is likely caused by a bug ' +1571 'in React. Please file an issue.',1572 );1573 }1574 if (parentFiber.flags & ContentReset) {1575 // Reset the text content of the parent before doing any insertions1576 resetTextContent(parent);1577 // Clear ContentReset from the effect tag1578 parentFiber.flags &= ~ContentReset;1579 }15801581 const before = getHostSibling(finishedWork);1582 // We only have the top Fiber that was inserted but we need to recurse down its1583 // children to find all the terminal nodes.1584 if (isContainer) {1585 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);1586 } else {1587 insertOrAppendPlacementNode(finishedWork, before, parent);1588 }1589}15901591function insertOrAppendPlacementNodeIntoContainer(1592 node: Fiber,1593 before: ?Instance,1594 parent: Container,1595): void {1596 const {tag} = node;1597 const isHost = tag === HostComponent || tag === HostText;1598 if (isHost) {1599 const stateNode = node.stateNode;1600 if (before) {1601 insertInContainerBefore(parent, stateNode, before);1602 } else {1603 appendChildToContainer(parent, stateNode);1604 }1605 } else if (tag === HostPortal) {1606 // If the insertion itself is a portal, then we don't want to traverse1607 // down its children. Instead, we'll get insertions from each child in1608 // the portal directly.1609 } else {1610 const child = node.child;1611 if (child !== null) {1612 insertOrAppendPlacementNodeIntoContainer(child, before, parent);1613 let sibling = child.sibling;1614 while (sibling !== null) {1615 insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);1616 sibling = sibling.sibling;1617 }1618 }1619 }1620}16211622function insertOrAppendPlacementNode(1623 node: Fiber,1624 before: ?Instance,1625 parent: Instance,1626): void {1627 const {tag} = node;1628 const isHost = tag === HostComponent || tag === HostText;1629 if (isHost) {1630 const stateNode = node.stateNode;1631 if (before) {1632 insertBefore(parent, stateNode, before);1633 } else {1634 appendChild(parent, stateNode);1635 }1636 } else if (tag === HostPortal) {1637 // If the insertion itself is a portal, then we don't want to traverse1638 // down its children. Instead, we'll get insertions from each child in1639 // the portal directly.1640 } else {1641 const child = node.child;1642 if (child !== null) {1643 insertOrAppendPlacementNode(child, before, parent);1644 let sibling = child.sibling;1645 while (sibling !== null) {1646 insertOrAppendPlacementNode(sibling, before, parent);1647 sibling = sibling.sibling;1648 }1649 }1650 }1651}16521653function unmountHostComponents(1654 finishedRoot: FiberRoot,1655 current: Fiber,1656 nearestMountedAncestor: Fiber,1657): void {1658 // We only have the top Fiber that was deleted but we need to recurse down its1659 // children to find all the terminal nodes.1660 let node: Fiber = current;16611662 // Each iteration, currentParent is populated with node's host parent if not1663 // currentParentIsValid.1664 let currentParentIsValid = false;16651666 // Note: these two variables *must* always be updated together.1667 let currentParent;1668 let currentParentIsContainer;16691670 while (true) {1671 if (!currentParentIsValid) {1672 let parent = node.return;1673 findParent: while (true) {1674 invariant(1675 parent !== null,1676 'Expected to find a host parent. This error is likely caused by ' +1677 'a bug in React. Please file an issue.',1678 );1679 const parentStateNode = parent.stateNode;1680 switch (parent.tag) {1681 case HostComponent:1682 currentParent = parentStateNode;1683 currentParentIsContainer = false;1684 break findParent;1685 case HostRoot:1686 currentParent = parentStateNode.containerInfo;1687 currentParentIsContainer = true;1688 break findParent;1689 case HostPortal:1690 currentParent = parentStateNode.containerInfo;1691 currentParentIsContainer = true;1692 break findParent;1693 }1694 parent = parent.return;1695 }1696 currentParentIsValid = true;1697 }16981699 if (node.tag === HostComponent || node.tag === HostText) {1700 commitNestedUnmounts(finishedRoot, node, nearestMountedAncestor);1701 // After all the children have unmounted, it is now safe to remove the1702 // node from the tree.1703 if (currentParentIsContainer) {1704 removeChildFromContainer(1705 ((currentParent: any): Container),1706 (node.stateNode: Instance | TextInstance),1707 );1708 } else {1709 removeChild(1710 ((currentParent: any): Instance),1711 (node.stateNode: Instance | TextInstance),1712 );1713 }1714 // Don't visit children because we already visited them.1715 } else if (1716 enableSuspenseServerRenderer &&1717 node.tag === DehydratedFragment1718 ) {1719 if (enableSuspenseCallback) {1720 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1721 if (hydrationCallbacks !== null) {1722 const onDeleted = hydrationCallbacks.onDeleted;1723 if (onDeleted) {1724 onDeleted((node.stateNode: SuspenseInstance));1725 }1726 }1727 }17281729 // Delete the dehydrated suspense boundary and all of its content.1730 if (currentParentIsContainer) {1731 clearSuspenseBoundaryFromContainer(1732 ((currentParent: any): Container),1733 (node.stateNode: SuspenseInstance),1734 );1735 } else {1736 clearSuspenseBoundary(1737 ((currentParent: any): Instance),1738 (node.stateNode: SuspenseInstance),1739 );1740 }1741 } else if (node.tag === HostPortal) {1742 if (node.child !== null) {1743 // When we go into a portal, it becomes the parent to remove from.1744 // We will reassign it back when we pop the portal on the way up.1745 currentParent = node.stateNode.containerInfo;1746 currentParentIsContainer = true;1747 // Visit children because portals might contain host components.1748 node.child.return = node;1749 node = node.child;1750 continue;1751 }1752 } else {1753 commitUnmount(finishedRoot, node, nearestMountedAncestor);1754 // Visit children because we may find more host components below.1755 if (node.child !== null) {1756 node.child.return = node;1757 node = node.child;1758 continue;1759 }1760 }1761 if (node === current) {1762 return;1763 }1764 while (node.sibling === null) {1765 if (node.return === null || node.return === current) {1766 return;1767 }1768 node = node.return;1769 if (node.tag === HostPortal) {1770 // When we go out of the portal, we need to restore the parent.1771 // Since we don't keep a stack of them, we will search for it.1772 currentParentIsValid = false;1773 }1774 }1775 node.sibling.return = node.return;1776 node = node.sibling;1777 }1778}17791780function commitDeletion(1781 finishedRoot: FiberRoot,1782 current: Fiber,1783 nearestMountedAncestor: Fiber,1784): void {1785 if (supportsMutation) {1786 // Recursively delete all host nodes from the parent.1787 // Detach refs and call componentWillUnmount() on the whole subtree.1788 unmountHostComponents(finishedRoot, current, nearestMountedAncestor);1789 } else {1790 // Detach refs and call componentWillUnmount() on the whole subtree.1791 commitNestedUnmounts(finishedRoot, current, nearestMountedAncestor);1792 }17931794 detachFiberMutation(current);1795}17961797function commitWork(current: Fiber | null, finishedWork: Fiber): void {1798 if (!supportsMutation) {1799 switch (finishedWork.tag) {1800 case FunctionComponent:1801 case ForwardRef:1802 case MemoComponent:1803 case SimpleMemoComponent: {1804 // Layout effects are destroyed during the mutation phase so that all1805 // destroy functions for all fibers are called before any create functions.1806 // This prevents sibling component effects from interfering with each other,1807 // e.g. a destroy function in one component should never override a ref set1808 // by a create function in another component during the same commit.1809 if (1810 enableProfilerTimer &&1811 enableProfilerCommitHooks &&1812 finishedWork.mode & ProfileMode1813 ) {1814 try {1815 startLayoutEffectTimer();1816 commitHookEffectListUnmount(1817 HookLayout | HookHasEffect,1818 finishedWork,1819 finishedWork.return,1820 );1821 } finally {1822 recordLayoutEffectDuration(finishedWork);1823 }1824 } else {1825 commitHookEffectListUnmount(1826 HookLayout | HookHasEffect,1827 finishedWork,1828 finishedWork.return,1829 );1830 }1831 return;1832 }1833 case Profiler: {1834 return;1835 }1836 case SuspenseComponent: {1837 commitSuspenseComponent(finishedWork);1838 attachSuspenseRetryListeners(finishedWork);1839 return;1840 }1841 case SuspenseListComponent: {1842 attachSuspenseRetryListeners(finishedWork);1843 return;1844 }1845 case HostRoot: {1846 if (supportsHydration) {1847 const root: FiberRoot = finishedWork.stateNode;1848 if (root.hydrate) {1849 // We've just hydrated. No need to hydrate again.1850 root.hydrate = false;1851 commitHydratedContainer(root.containerInfo);1852 }1853 }1854 break;1855 }1856 case OffscreenComponent:1857 case LegacyHiddenComponent: {1858 return;1859 }1860 }18611862 commitContainer(finishedWork);1863 return;1864 }18651866 switch (finishedWork.tag) {1867 case FunctionComponent:1868 case ForwardRef:1869 case MemoComponent:1870 case SimpleMemoComponent: {1871 // Layout effects are destroyed during the mutation phase so that all1872 // destroy functions for all fibers are called before any create functions.1873 // This prevents sibling component effects from interfering with each other,1874 // e.g. a destroy function in one component should never override a ref set1875 // by a create function in another component during the same commit.1876 if (1877 enableProfilerTimer &&1878 enableProfilerCommitHooks &&1879 finishedWork.mode & ProfileMode1880 ) {1881 try {1882 startLayoutEffectTimer();1883 commitHookEffectListUnmount(1884 HookLayout | HookHasEffect,1885 finishedWork,1886 finishedWork.return,1887 );1888 } finally {1889 recordLayoutEffectDuration(finishedWork);1890 }1891 } else {1892 commitHookEffectListUnmount(1893 HookLayout | HookHasEffect,1894 finishedWork,1895 finishedWork.return,1896 );1897 }1898 return;1899 }1900 case ClassComponent: {1901 return;1902 }1903 case HostComponent: {1904 const instance: Instance = finishedWork.stateNode;1905 if (instance != null) {1906 // Commit the work prepared earlier.1907 const newProps = finishedWork.memoizedProps;1908 // For hydration we reuse the update path but we treat the oldProps1909 // as the newProps. The updatePayload will contain the real change in1910 // this case.1911 const oldProps = current !== null ? current.memoizedProps : newProps;1912 const type = finishedWork.type;1913 // TODO: Type the updateQueue to be specific to host components.1914 const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);1915 finishedWork.updateQueue = null;1916 if (updatePayload !== null) {1917 commitUpdate(1918 instance,1919 updatePayload,1920 type,1921 oldProps,1922 newProps,1923 finishedWork,1924 );1925 }1926 }1927 return;1928 }1929 case HostText: {1930 invariant(1931 finishedWork.stateNode !== null,1932 'This should have a text node initialized. This error is likely ' +1933 'caused by a bug in React. Please file an issue.',1934 );1935 const textInstance: TextInstance = finishedWork.stateNode;1936 const newText: string = finishedWork.memoizedProps;1937 // For hydration we reuse the update path but we treat the oldProps1938 // as the newProps. The updatePayload will contain the real change in1939 // this case.1940 const oldText: string =1941 current !== null ? current.memoizedProps : newText;1942 commitTextUpdate(textInstance, oldText, newText);1943 return;1944 }1945 case HostRoot: {1946 if (supportsHydration) {1947 const root: FiberRoot = finishedWork.stateNode;1948 if (root.hydrate) {1949 // We've just hydrated. No need to hydrate again.1950 root.hydrate = false;1951 commitHydratedContainer(root.containerInfo);1952 }1953 }1954 return;1955 }1956 case Profiler: {1957 return;1958 }1959 case SuspenseComponent: {1960 commitSuspenseComponent(finishedWork);1961 attachSuspenseRetryListeners(finishedWork);1962 return;1963 }1964 case SuspenseListComponent: {1965 attachSuspenseRetryListeners(finishedWork);1966 return;1967 }1968 case IncompleteClassComponent: {1969 return;1970 }1971 case ScopeComponent: {1972 if (enableScopeAPI) {1973 const scopeInstance = finishedWork.stateNode;1974 prepareScopeUpdate(scopeInstance, finishedWork);1975 return;1976 }1977 break;1978 }1979 case OffscreenComponent:1980 case LegacyHiddenComponent: {1981 const newState: OffscreenState | null = finishedWork.memoizedState;1982 const isHidden = newState !== null;1983 hideOrUnhideAllChildren(finishedWork, isHidden);1984 return;1985 }1986 }1987 invariant(1988 false,1989 'This unit of work tag should not have side-effects. This error is ' +1990 'likely caused by a bug in React. Please file an issue.',1991 );1992}19931994function commitSuspenseComponent(finishedWork: Fiber) {1995 const newState: SuspenseState | null = finishedWork.memoizedState;19961997 if (newState !== null) {1998 markCommitTimeOfFallback();19992000 if (supportsMutation) {2001 // Hide the Offscreen component that contains the primary children. TODO:2002 // Ideally, this effect would have been scheduled on the Offscreen fiber2003 // itself. That's how unhiding works: the Offscreen component schedules an2004 // effect on itself. However, in this case, the component didn't complete,2005 // so the fiber was never added to the effect list in the normal path. We2006 // could have appended it to the effect list in the Suspense component's2007 // second pass, but doing it this way is less complicated. This would be2008 // simpler if we got rid of the effect list and traversed the tree, like2009 // we're planning to do.2010 const primaryChildParent: Fiber = (finishedWork.child: any);2011 hideOrUnhideAllChildren(primaryChildParent, true);2012 }2013 }20142015 if (enableSuspenseCallback && newState !== null) {2016 const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;2017 if (typeof suspenseCallback === 'function') {2018 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);2019 if (wakeables !== null) {2020 suspenseCallback(new Set(wakeables));2021 }2022 } else if (__DEV__) {2023 if (suspenseCallback !== undefined) {2024 console.error('Unexpected type for suspenseCallback.');2025 }2026 }2027 }2028}20292030function commitSuspenseHydrationCallbacks(2031 finishedRoot: FiberRoot,2032 finishedWork: Fiber,2033) {2034 if (!supportsHydration) {2035 return;2036 }2037 const newState: SuspenseState | null = finishedWork.memoizedState;2038 if (newState === null) {2039 const current = finishedWork.alternate;2040 if (current !== null) {2041 const prevState: SuspenseState | null = current.memoizedState;2042 if (prevState !== null) {2043 const suspenseInstance = prevState.dehydrated;2044 if (suspenseInstance !== null) {2045 commitHydratedSuspenseInstance(suspenseInstance);2046 if (enableSuspenseCallback) {2047 const hydrationCallbacks = finishedRoot.hydrationCallbacks;2048 if (hydrationCallbacks !== null) {2049 const onHydrated = hydrationCallbacks.onHydrated;2050 if (onHydrated) {2051 onHydrated(suspenseInstance);2052 }2053 }2054 }2055 }2056 }2057 }2058 }2059}20602061function attachSuspenseRetryListeners(finishedWork: Fiber) {2062 // If this boundary just timed out, then it will have a set of wakeables.2063 // For each wakeable, attach a listener so that when it resolves, React2064 // attempts to re-render the boundary in the primary (pre-timeout) state.2065 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);2066 if (wakeables !== null) {2067 finishedWork.updateQueue = null;2068 let retryCache = finishedWork.stateNode;2069 if (retryCache === null) {2070 retryCache = finishedWork.stateNode = new PossiblyWeakSet();2071 }2072 wakeables.forEach(wakeable => {2073 // Memoize using the boundary fiber to prevent redundant listeners.2074 const retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);2075 if (!retryCache.has(wakeable)) {2076 retryCache.add(wakeable);20772078 if (enableUpdaterTracking) {2079 if (isDevToolsPresent) {2080 if (inProgressLanes !== null && inProgressRoot !== null) {2081 // If we have pending work still, associate the original updaters with it.2082 restorePendingUpdaters(inProgressRoot, inProgressLanes);2083 } else {2084 throw Error(2085 'Expected finished root and lanes to be set. This is a bug in React.',2086 );2087 }2088 }2089 }20902091 wakeable.then(retry, retry);2092 }2093 });2094 }2095}20962097// This function detects when a Suspense boundary goes from visible to hidden.2098// It returns false if the boundary is already hidden.2099// TODO: Use an effect tag.2100export function isSuspenseBoundaryBeingHidden(2101 current: Fiber | null,2102 finishedWork: Fiber,2103): boolean {2104 if (current !== null) {2105 const oldState: SuspenseState | null = current.memoizedState;2106 if (oldState === null || oldState.dehydrated !== null) {2107 const newState: SuspenseState | null = finishedWork.memoizedState;2108 return newState !== null && newState.dehydrated === null;2109 }2110 }2111 return false;2112}21132114function commitResetTextContent(current: Fiber) {2115 if (!supportsMutation) {2116 return;2117 }2118 resetTextContent(current.stateNode);2119}21202121export function commitMutationEffects(2122 root: FiberRoot,2123 firstChild: Fiber,2124 committedLanes: Lanes,2125) {2126 inProgressLanes = committedLanes;2127 inProgressRoot = root;2128 nextEffect = firstChild;21292130 commitMutationEffects_begin(root);21312132 inProgressLanes = null;2133 inProgressRoot = null;2134}21352136function commitMutationEffects_begin(root: FiberRoot) {2137 while (nextEffect !== null) {2138 const fiber = nextEffect;21392140 // TODO: Should wrap this in flags check, too, as optimization2141 const deletions = fiber.deletions;2142 if (deletions !== null) {2143 for (let i = 0; i < deletions.length; i++) {2144 const childToDelete = deletions[i];2145 if (__DEV__) {2146 invokeGuardedCallback(2147 null,2148 commitDeletion,2149 null,2150 root,2151 childToDelete,2152 fiber,2153 );2154 if (hasCaughtError()) {2155 const error = clearCaughtError();2156 captureCommitPhaseError(childToDelete, fiber, error);2157 }2158 } else {2159 try {2160 commitDeletion(root, childToDelete, fiber);2161 } catch (error) {2162 captureCommitPhaseError(childToDelete, fiber, error);2163 }2164 }2165 }2166 }21672168 const child = fiber.child;2169 if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {2170 ensureCorrectReturnPointer(child, fiber);2171 nextEffect = child;2172 } else {2173 commitMutationEffects_complete(root);2174 }2175 }2176}21772178function commitMutationEffects_complete(root: FiberRoot) {2179 while (nextEffect !== null) {2180 const fiber = nextEffect;2181 if (__DEV__) {2182 setCurrentDebugFiberInDEV(fiber);2183 invokeGuardedCallback(2184 null,2185 commitMutationEffectsOnFiber,2186 null,2187 fiber,2188 root,2189 );2190 if (hasCaughtError()) {2191 const error = clearCaughtError();2192 captureCommitPhaseError(fiber, fiber.return, error);2193 }2194 resetCurrentDebugFiberInDEV();2195 } else {2196 try {2197 commitMutationEffectsOnFiber(fiber, root);2198 } catch (error) {2199 captureCommitPhaseError(fiber, fiber.return, error);2200 }2201 }22022203 const sibling = fiber.sibling;2204 if (sibling !== null) {2205 ensureCorrectReturnPointer(sibling, fiber.return);2206 nextEffect = sibling;2207 return;2208 }22092210 nextEffect = fiber.return;2211 }2212}22132214function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {2215 const flags = finishedWork.flags;22162217 if (flags & ContentReset) {2218 commitResetTextContent(finishedWork);2219 }22202221 if (flags & Ref) {2222 const current = finishedWork.alternate;2223 if (current !== null) {2224 commitDetachRef(current);2225 }2226 if (enableScopeAPI) {2227 // TODO: This is a temporary solution that allowed us to transition away2228 // from React Flare on www.2229 if (finishedWork.tag === ScopeComponent) {2230 commitAttachRef(finishedWork);2231 }2232 }2233 }22342235 // The following switch statement is only concerned about placement,2236 // updates, and deletions. To avoid needing to add a case for every possible2237 // bitmap value, we remove the secondary effects from the effect tag and2238 // switch on that value.2239 const primaryFlags = flags & (Placement | Update | Hydrating);2240 outer: switch (primaryFlags) {2241 case Placement: {2242 commitPlacement(finishedWork);2243 // Clear the "placement" from effect tag so that we know that this is2244 // inserted, before any life-cycles like componentDidMount gets called.2245 // TODO: findDOMNode doesn't rely on this any more but isMounted does2246 // and isMounted is deprecated anyway so we should be able to kill this.2247 finishedWork.flags &= ~Placement;2248 break;2249 }2250 case PlacementAndUpdate: {2251 // Placement2252 commitPlacement(finishedWork);2253 // Clear the "placement" from effect tag so that we know that this is2254 // inserted, before any life-cycles like componentDidMount gets called.2255 finishedWork.flags &= ~Placement;22562257 // Update2258 const current = finishedWork.alternate;2259 commitWork(current, finishedWork);2260 break;2261 }2262 case Hydrating: {2263 finishedWork.flags &= ~Hydrating;2264 break;2265 }2266 case HydratingAndUpdate: {2267 finishedWork.flags &= ~Hydrating;22682269 // Update2270 const current = finishedWork.alternate;2271 commitWork(current, finishedWork);2272 break;2273 }2274 case Update: {2275 const current = finishedWork.alternate;2276 commitWork(current, finishedWork);2277 break;2278 }2279 }2280}22812282export function commitLayoutEffects(2283 finishedWork: Fiber,2284 root: FiberRoot,2285 committedLanes: Lanes,2286): void {2287 inProgressLanes = committedLanes;2288 inProgressRoot = root;2289 nextEffect = finishedWork;22902291 commitLayoutEffects_begin(finishedWork, root, committedLanes);22922293 inProgressLanes = null;2294 inProgressRoot = null;2295}22962297function commitLayoutEffects_begin(2298 subtreeRoot: Fiber,2299 root: FiberRoot,2300 committedLanes: Lanes,2301) {2302 // Suspense layout effects semantics don't change for legacy roots.2303 const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;23042305 while (nextEffect !== null) {2306 const fiber = nextEffect;2307 const firstChild = fiber.child;23082309 if (2310 enableSuspenseLayoutEffectSemantics &&2311 fiber.tag === OffscreenComponent &&2312 isModernRoot2313 ) {2314 // Keep track of the current Offscreen stack's state.2315 const isHidden = fiber.memoizedState !== null;2316 const newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden;2317 if (newOffscreenSubtreeIsHidden) {2318 // The Offscreen tree is hidden. Skip over its layout effects.2319 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2320 continue;2321 } else {2322 if ((fiber.subtreeFlags & LayoutMask) !== NoFlags) {2323 const current = fiber.alternate;2324 const wasHidden = current !== null && current.memoizedState !== null;2325 const newOffscreenSubtreeWasHidden =2326 wasHidden || offscreenSubtreeWasHidden;2327 const prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden;2328 const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden;23292330 // Traverse the Offscreen subtree with the current Offscreen as the root.2331 offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden;2332 offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden;2333 let child = firstChild;2334 while (child !== null) {2335 nextEffect = child;2336 commitLayoutEffects_begin(2337 child, // New root; bubble back up to here and stop.2338 root,2339 committedLanes,2340 );2341 child = child.sibling;2342 }23432344 // Restore Offscreen state and resume in our-progress traversal.2345 nextEffect = fiber;2346 offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden;2347 offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden;2348 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);23492350 continue;2351 }2352 }2353 }23542355 if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null) {2356 ensureCorrectReturnPointer(firstChild, fiber);2357 nextEffect = firstChild;2358 } else {2359 if (enableSuspenseLayoutEffectSemantics && isModernRoot) {2360 const visibilityChanged =2361 !offscreenSubtreeIsHidden && offscreenSubtreeWasHidden;23622363 // TODO (Offscreen) Also check: subtreeFlags & LayoutStatic2364 if (visibilityChanged && firstChild !== null) {2365 // We've just shown or hidden a Offscreen tree that contains layout effects.2366 // We only enter this code path for subtrees that are updated,2367 // because newly mounted ones would pass the LayoutMask check above.2368 ensureCorrectReturnPointer(firstChild, fiber);2369 nextEffect = firstChild;2370 continue;2371 }2372 }23732374 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2375 }2376 }2377}23782379function commitLayoutMountEffects_complete(2380 subtreeRoot: Fiber,2381 root: FiberRoot,2382 committedLanes: Lanes,2383) {2384 // Suspense layout effects semantics don't change for legacy roots.2385 const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;23862387 while (nextEffect !== null) {2388 const fiber = nextEffect;23892390 if (2391 enableSuspenseLayoutEffectSemantics &&2392 isModernRoot &&2393 offscreenSubtreeWasHidden &&2394 !offscreenSubtreeIsHidden2395 ) {2396 // Inside of an Offscreen subtree that changed visibility during this commit.2397 // If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)2398 // but if it was just shown, we need to (re)create the effects now.2399 // TODO (Offscreen) Check: flags & LayoutStatic2400 switch (fiber.tag) {2401 case FunctionComponent:2402 case ForwardRef:2403 case SimpleMemoComponent: {2404 if (2405 enableProfilerTimer &&2406 enableProfilerCommitHooks &&2407 fiber.mode & ProfileMode2408 ) {2409 try {2410 startLayoutEffectTimer();2411 safelyCallCommitHookLayoutEffectListMount(fiber, fiber.return);2412 } finally {2413 recordLayoutEffectDuration(fiber);2414 }2415 } else {2416 safelyCallCommitHookLayoutEffectListMount(fiber, fiber.return);2417 }2418 break;2419 }2420 case ClassComponent: {2421 const instance = fiber.stateNode;2422 if (typeof instance.componentDidMount === 'function') {2423 safelyCallComponentDidMount(fiber, fiber.return, instance);2424 }2425 break;2426 }2427 }24282429 // TODO (Offscreen) Check flags & RefStatic2430 switch (fiber.tag) {2431 case ClassComponent:2432 case HostComponent:2433 safelyAttachRef(fiber, fiber.return);2434 break;2435 }2436 } else if ((fiber.flags & LayoutMask) !== NoFlags) {2437 const current = fiber.alternate;2438 if (__DEV__) {2439 setCurrentDebugFiberInDEV(fiber);2440 invokeGuardedCallback(2441 null,2442 commitLayoutEffectOnFiber,2443 null,2444 root,2445 current,2446 fiber,2447 committedLanes,2448 );2449 if (hasCaughtError()) {2450 const error = clearCaughtError();2451 captureCommitPhaseError(fiber, fiber.return, error);2452 }2453 resetCurrentDebugFiberInDEV();2454 } else {2455 try {2456 commitLayoutEffectOnFiber(root, current, fiber, committedLanes);2457 } catch (error) {2458 captureCommitPhaseError(fiber, fiber.return, error);2459 }2460 }2461 }24622463 if (fiber === subtreeRoot) {2464 nextEffect = null;2465 return;2466 }24672468 const sibling = fiber.sibling;2469 if (sibling !== null) {2470 ensureCorrectReturnPointer(sibling, fiber.return);2471 nextEffect = sibling;2472 return;2473 }24742475 nextEffect = fiber.return;2476 }2477}24782479export function commitPassiveMountEffects(2480 root: FiberRoot,2481 finishedWork: Fiber,2482): void {2483 nextEffect = finishedWork;2484 commitPassiveMountEffects_begin(finishedWork, root);2485}24862487function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {2488 while (nextEffect !== null) {2489 const fiber = nextEffect;2490 const firstChild = fiber.child;2491 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {2492 ensureCorrectReturnPointer(firstChild, fiber);2493 nextEffect = firstChild;2494 } else {2495 commitPassiveMountEffects_complete(subtreeRoot, root);2496 }2497 }2498}24992500function commitPassiveMountEffects_complete(2501 subtreeRoot: Fiber,2502 root: FiberRoot,2503) {2504 while (nextEffect !== null) {2505 const fiber = nextEffect;2506 if ((fiber.flags & Passive) !== NoFlags) {2507 if (__DEV__) {2508 setCurrentDebugFiberInDEV(fiber);2509 invokeGuardedCallback(2510 null,2511 commitPassiveMountOnFiber,2512 null,2513 root,2514 fiber,2515 );2516 if (hasCaughtError()) {2517 const error = clearCaughtError();2518 captureCommitPhaseError(fiber, fiber.return, error);2519 }2520 resetCurrentDebugFiberInDEV();2521 } else {2522 try {2523 commitPassiveMountOnFiber(root, fiber);2524 } catch (error) {2525 captureCommitPhaseError(fiber, fiber.return, error);2526 }2527 }2528 }25292530 if (fiber === subtreeRoot) {2531 nextEffect = null;2532 return;2533 }25342535 const sibling = fiber.sibling;2536 if (sibling !== null) {2537 ensureCorrectReturnPointer(sibling, fiber.return);2538 nextEffect = sibling;2539 return;2540 }25412542 nextEffect = fiber.return;2543 }2544}25452546function commitPassiveMountOnFiber(2547 finishedRoot: FiberRoot,2548 finishedWork: Fiber,2549): void {2550 switch (finishedWork.tag) {2551 case FunctionComponent:2552 case ForwardRef:2553 case SimpleMemoComponent: {2554 if (2555 enableProfilerTimer &&2556 enableProfilerCommitHooks &&2557 finishedWork.mode & ProfileMode2558 ) {2559 startPassiveEffectTimer();2560 try {2561 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2562 } finally {2563 recordPassiveEffectDuration(finishedWork);2564 }2565 } else {2566 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2567 }2568 break;2569 }2570 }2571}25722573export function commitPassiveUnmountEffects(firstChild: Fiber): void {2574 nextEffect = firstChild;2575 commitPassiveUnmountEffects_begin();2576}25772578function commitPassiveUnmountEffects_begin() {2579 while (nextEffect !== null) {2580 const fiber = nextEffect;2581 const child = fiber.child;25822583 if ((nextEffect.flags & ChildDeletion) !== NoFlags) {2584 const deletions = fiber.deletions;2585 if (deletions !== null) {2586 for (let i = 0; i < deletions.length; i++) {2587 const fiberToDelete = deletions[i];2588 nextEffect = fiberToDelete;2589 commitPassiveUnmountEffectsInsideOfDeletedTree_begin(2590 fiberToDelete,2591 fiber,2592 );2593 }25942595 if (deletedTreeCleanUpLevel >= 1) {2596 // A fiber was deleted from this parent fiber, but it's still part of2597 // the previous (alternate) parent fiber's list of children. Because2598 // children are a linked list, an earlier sibling that's still alive2599 // will be connected to the deleted fiber via its `alternate`:2600 //2601 // live fiber2602 // --alternate--> previous live fiber2603 // --sibling--> deleted fiber2604 //2605 // We can't disconnect `alternate` on nodes that haven't been deleted2606 // yet, but we can disconnect the `sibling` and `child` pointers.2607 const previousFiber = fiber.alternate;2608 if (previousFiber !== null) {2609 let detachedChild = previousFiber.child;2610 if (detachedChild !== null) {2611 previousFiber.child = null;2612 do {2613 const detachedSibling = detachedChild.sibling;2614 detachedChild.sibling = null;2615 detachedChild = detachedSibling;2616 } while (detachedChild !== null);2617 }2618 }2619 }26202621 nextEffect = fiber;2622 }2623 }26242625 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && child !== null) {2626 ensureCorrectReturnPointer(child, fiber);2627 nextEffect = child;2628 } else {2629 commitPassiveUnmountEffects_complete();2630 }2631 }2632}26332634function commitPassiveUnmountEffects_complete() {2635 while (nextEffect !== null) {2636 const fiber = nextEffect;2637 if ((fiber.flags & Passive) !== NoFlags) {2638 setCurrentDebugFiberInDEV(fiber);2639 commitPassiveUnmountOnFiber(fiber);2640 resetCurrentDebugFiberInDEV();2641 }26422643 const sibling = fiber.sibling;2644 if (sibling !== null) {2645 ensureCorrectReturnPointer(sibling, fiber.return);2646 nextEffect = sibling;2647 return;2648 }26492650 nextEffect = fiber.return;2651 }2652}26532654function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {2655 switch (finishedWork.tag) {2656 case FunctionComponent:2657 case ForwardRef:2658 case SimpleMemoComponent: {2659 if (2660 enableProfilerTimer &&2661 enableProfilerCommitHooks &&2662 finishedWork.mode & ProfileMode2663 ) {2664 startPassiveEffectTimer();2665 commitHookEffectListUnmount(2666 HookPassive | HookHasEffect,2667 finishedWork,2668 finishedWork.return,2669 );2670 recordPassiveEffectDuration(finishedWork);2671 } else {2672 commitHookEffectListUnmount(2673 HookPassive | HookHasEffect,2674 finishedWork,2675 finishedWork.return,2676 );2677 }2678 break;2679 }2680 }2681}26822683function commitPassiveUnmountEffectsInsideOfDeletedTree_begin(2684 deletedSubtreeRoot: Fiber,2685 nearestMountedAncestor: Fiber | null,2686) {2687 while (nextEffect !== null) {2688 const fiber = nextEffect;26892690 // Deletion effects fire in parent -> child order2691 // TODO: Check if fiber has a PassiveStatic flag2692 setCurrentDebugFiberInDEV(fiber);2693 commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor);2694 resetCurrentDebugFiberInDEV();26952696 const child = fiber.child;2697 // TODO: Only traverse subtree if it has a PassiveStatic flag. (But, if we2698 // do this, still need to handle `deletedTreeCleanUpLevel` correctly.)2699 if (child !== null) {2700 ensureCorrectReturnPointer(child, fiber);2701 nextEffect = child;2702 } else {2703 commitPassiveUnmountEffectsInsideOfDeletedTree_complete(2704 deletedSubtreeRoot,2705 );2706 }2707 }2708}27092710function commitPassiveUnmountEffectsInsideOfDeletedTree_complete(2711 deletedSubtreeRoot: Fiber,2712) {2713 while (nextEffect !== null) {2714 const fiber = nextEffect;2715 const sibling = fiber.sibling;2716 const returnFiber = fiber.return;27172718 if (deletedTreeCleanUpLevel >= 2) {2719 // Recursively traverse the entire deleted tree and clean up fiber fields.2720 // This is more aggressive than ideal, and the long term goal is to only2721 // have to detach the deleted tree at the root.2722 detachFiberAfterEffects(fiber);2723 if (fiber === deletedSubtreeRoot) {2724 nextEffect = null;2725 return;2726 }2727 } else {2728 // This is the default branch (level 0). We do not recursively clear all2729 // the fiber fields. Only the root of the deleted subtree.2730 if (fiber === deletedSubtreeRoot) {2731 detachFiberAfterEffects(fiber);2732 nextEffect = null;2733 return;2734 }2735 }27362737 if (sibling !== null) {2738 ensureCorrectReturnPointer(sibling, returnFiber);2739 nextEffect = sibling;2740 return;2741 }27422743 nextEffect = returnFiber;2744 }2745}
...
ReactFiberCommitWork.new.js
Source:ReactFiberCommitWork.new.js
...1346 }1347 fiber.return = null;1348}13491350function detachFiberAfterEffects(fiber: Fiber) {1351 const alternate = fiber.alternate;1352 if (alternate !== null) {1353 fiber.alternate = null;1354 detachFiberAfterEffects(alternate);1355 }13561357 // Note: Defensively using negation instead of < in case1358 // `deletedTreeCleanUpLevel` is undefined.1359 if (!(deletedTreeCleanUpLevel >= 2)) {1360 // This is the default branch (level 0).1361 fiber.child = null;1362 fiber.deletions = null;1363 fiber.dependencies = null;1364 fiber.memoizedProps = null;1365 fiber.memoizedState = null;1366 fiber.pendingProps = null;1367 fiber.sibling = null;1368 fiber.stateNode = null;1369 fiber.updateQueue = null;13701371 if (__DEV__) {1372 fiber._debugOwner = null;1373 }1374 } else {1375 // Clear cyclical Fiber fields. This level alone is designed to roughly1376 // approximate the planned Fiber refactor. In that world, `setState` will be1377 // bound to a special "instance" object instead of a Fiber. The Instance1378 // object will not have any of these fields. It will only be connected to1379 // the fiber tree via a single link at the root. So if this level alone is1380 // sufficient to fix memory issues, that bodes well for our plans.1381 fiber.child = null;1382 fiber.deletions = null;1383 fiber.sibling = null;13841385 // The `stateNode` is cyclical because on host nodes it points to the host1386 // tree, which has its own pointers to children, parents, and siblings.1387 // The other host nodes also point back to fibers, so we should detach that1388 // one, too.1389 if (fiber.tag === HostComponent) {1390 const hostInstance: Instance = fiber.stateNode;1391 if (hostInstance !== null) {1392 detachDeletedInstance(hostInstance);1393 }1394 }1395 fiber.stateNode = null;13961397 // I'm intentionally not clearing the `return` field in this level. We1398 // already disconnect the `return` pointer at the root of the deleted1399 // subtree (in `detachFiberMutation`). Besides, `return` by itself is not1400 // cyclical â it's only cyclical when combined with `child`, `sibling`, and1401 // `alternate`. But we'll clear it in the next level anyway, just in case.14021403 if (__DEV__) {1404 fiber._debugOwner = null;1405 }14061407 if (deletedTreeCleanUpLevel >= 3) {1408 // Theoretically, nothing in here should be necessary, because we already1409 // disconnected the fiber from the tree. So even if something leaks this1410 // particular fiber, it won't leak anything else1411 //1412 // The purpose of this branch is to be super aggressive so we can measure1413 // if there's any difference in memory impact. If there is, that could1414 // indicate a React leak we don't know about.1415 fiber.return = null;1416 fiber.dependencies = null;1417 fiber.memoizedProps = null;1418 fiber.memoizedState = null;1419 fiber.pendingProps = null;1420 fiber.stateNode = null;1421 // TODO: Move to `commitPassiveUnmountInsideDeletedTreeOnFiber` instead.1422 fiber.updateQueue = null;1423 }1424 }1425}14261427function emptyPortalContainer(current: Fiber) {1428 if (!supportsPersistence) {1429 return;1430 }14311432 const portal: {1433 containerInfo: Container,1434 pendingChildren: ChildSet,1435 ...1436 } = current.stateNode;1437 const {containerInfo} = portal;1438 const emptyChildSet = createContainerChildSet(containerInfo);1439 replaceContainerChildren(containerInfo, emptyChildSet);1440}14411442function commitContainer(finishedWork: Fiber) {1443 if (!supportsPersistence) {1444 return;1445 }14461447 switch (finishedWork.tag) {1448 case ClassComponent:1449 case HostComponent:1450 case HostText: {1451 return;1452 }1453 case HostRoot:1454 case HostPortal: {1455 const portalOrRoot: {1456 containerInfo: Container,1457 pendingChildren: ChildSet,1458 ...1459 } = finishedWork.stateNode;1460 const {containerInfo, pendingChildren} = portalOrRoot;1461 replaceContainerChildren(containerInfo, pendingChildren);1462 return;1463 }1464 }1465 invariant(1466 false,1467 'This unit of work tag should not have side-effects. This error is ' +1468 'likely caused by a bug in React. Please file an issue.',1469 );1470}14711472function getHostParentFiber(fiber: Fiber): Fiber {1473 let parent = fiber.return;1474 while (parent !== null) {1475 if (isHostParent(parent)) {1476 return parent;1477 }1478 parent = parent.return;1479 }1480 invariant(1481 false,1482 'Expected to find a host parent. This error is likely caused by a bug ' +1483 'in React. Please file an issue.',1484 );1485}14861487function isHostParent(fiber: Fiber): boolean {1488 return (1489 fiber.tag === HostComponent ||1490 fiber.tag === HostRoot ||1491 fiber.tag === HostPortal1492 );1493}14941495function getHostSibling(fiber: Fiber): ?Instance {1496 // We're going to search forward into the tree until we find a sibling host1497 // node. Unfortunately, if multiple insertions are done in a row we have to1498 // search past them. This leads to exponential search for the next sibling.1499 // TODO: Find a more efficient way to do this.1500 let node: Fiber = fiber;1501 siblings: while (true) {1502 // If we didn't find anything, let's try the next sibling.1503 while (node.sibling === null) {1504 if (node.return === null || isHostParent(node.return)) {1505 // If we pop out of the root or hit the parent the fiber we are the1506 // last sibling.1507 return null;1508 }1509 node = node.return;1510 }1511 node.sibling.return = node.return;1512 node = node.sibling;1513 while (1514 node.tag !== HostComponent &&1515 node.tag !== HostText &&1516 node.tag !== DehydratedFragment1517 ) {1518 // If it is not host node and, we might have a host node inside it.1519 // Try to search down until we find one.1520 if (node.flags & Placement) {1521 // If we don't have a child, try the siblings instead.1522 continue siblings;1523 }1524 // If we don't have a child, try the siblings instead.1525 // We also skip portals because they are not part of this host tree.1526 if (node.child === null || node.tag === HostPortal) {1527 continue siblings;1528 } else {1529 node.child.return = node;1530 node = node.child;1531 }1532 }1533 // Check if this host node is stable or about to be placed.1534 if (!(node.flags & Placement)) {1535 // Found it!1536 return node.stateNode;1537 }1538 }1539}15401541function commitPlacement(finishedWork: Fiber): void {1542 if (!supportsMutation) {1543 return;1544 }15451546 // Recursively insert all host nodes into the parent.1547 const parentFiber = getHostParentFiber(finishedWork);15481549 // Note: these two variables *must* always be updated together.1550 let parent;1551 let isContainer;1552 const parentStateNode = parentFiber.stateNode;1553 switch (parentFiber.tag) {1554 case HostComponent:1555 parent = parentStateNode;1556 isContainer = false;1557 break;1558 case HostRoot:1559 parent = parentStateNode.containerInfo;1560 isContainer = true;1561 break;1562 case HostPortal:1563 parent = parentStateNode.containerInfo;1564 isContainer = true;1565 break;1566 // eslint-disable-next-line-no-fallthrough1567 default:1568 invariant(1569 false,1570 'Invalid host parent fiber. This error is likely caused by a bug ' +1571 'in React. Please file an issue.',1572 );1573 }1574 if (parentFiber.flags & ContentReset) {1575 // Reset the text content of the parent before doing any insertions1576 resetTextContent(parent);1577 // Clear ContentReset from the effect tag1578 parentFiber.flags &= ~ContentReset;1579 }15801581 const before = getHostSibling(finishedWork);1582 // We only have the top Fiber that was inserted but we need to recurse down its1583 // children to find all the terminal nodes.1584 if (isContainer) {1585 insertOrAppendPlacementNodeIntoContainer(finishedWork, before, parent);1586 } else {1587 insertOrAppendPlacementNode(finishedWork, before, parent);1588 }1589}15901591function insertOrAppendPlacementNodeIntoContainer(1592 node: Fiber,1593 before: ?Instance,1594 parent: Container,1595): void {1596 const {tag} = node;1597 const isHost = tag === HostComponent || tag === HostText;1598 if (isHost) {1599 const stateNode = node.stateNode;1600 if (before) {1601 insertInContainerBefore(parent, stateNode, before);1602 } else {1603 appendChildToContainer(parent, stateNode);1604 }1605 } else if (tag === HostPortal) {1606 // If the insertion itself is a portal, then we don't want to traverse1607 // down its children. Instead, we'll get insertions from each child in1608 // the portal directly.1609 } else {1610 const child = node.child;1611 if (child !== null) {1612 insertOrAppendPlacementNodeIntoContainer(child, before, parent);1613 let sibling = child.sibling;1614 while (sibling !== null) {1615 insertOrAppendPlacementNodeIntoContainer(sibling, before, parent);1616 sibling = sibling.sibling;1617 }1618 }1619 }1620}16211622function insertOrAppendPlacementNode(1623 node: Fiber,1624 before: ?Instance,1625 parent: Instance,1626): void {1627 const {tag} = node;1628 const isHost = tag === HostComponent || tag === HostText;1629 if (isHost) {1630 const stateNode = node.stateNode;1631 if (before) {1632 insertBefore(parent, stateNode, before);1633 } else {1634 appendChild(parent, stateNode);1635 }1636 } else if (tag === HostPortal) {1637 // If the insertion itself is a portal, then we don't want to traverse1638 // down its children. Instead, we'll get insertions from each child in1639 // the portal directly.1640 } else {1641 const child = node.child;1642 if (child !== null) {1643 insertOrAppendPlacementNode(child, before, parent);1644 let sibling = child.sibling;1645 while (sibling !== null) {1646 insertOrAppendPlacementNode(sibling, before, parent);1647 sibling = sibling.sibling;1648 }1649 }1650 }1651}16521653function unmountHostComponents(1654 finishedRoot: FiberRoot,1655 current: Fiber,1656 nearestMountedAncestor: Fiber,1657): void {1658 // We only have the top Fiber that was deleted but we need to recurse down its1659 // children to find all the terminal nodes.1660 let node: Fiber = current;16611662 // Each iteration, currentParent is populated with node's host parent if not1663 // currentParentIsValid.1664 let currentParentIsValid = false;16651666 // Note: these two variables *must* always be updated together.1667 let currentParent;1668 let currentParentIsContainer;16691670 while (true) {1671 if (!currentParentIsValid) {1672 let parent = node.return;1673 findParent: while (true) {1674 invariant(1675 parent !== null,1676 'Expected to find a host parent. This error is likely caused by ' +1677 'a bug in React. Please file an issue.',1678 );1679 const parentStateNode = parent.stateNode;1680 switch (parent.tag) {1681 case HostComponent:1682 currentParent = parentStateNode;1683 currentParentIsContainer = false;1684 break findParent;1685 case HostRoot:1686 currentParent = parentStateNode.containerInfo;1687 currentParentIsContainer = true;1688 break findParent;1689 case HostPortal:1690 currentParent = parentStateNode.containerInfo;1691 currentParentIsContainer = true;1692 break findParent;1693 }1694 parent = parent.return;1695 }1696 currentParentIsValid = true;1697 }16981699 if (node.tag === HostComponent || node.tag === HostText) {1700 commitNestedUnmounts(finishedRoot, node, nearestMountedAncestor);1701 // After all the children have unmounted, it is now safe to remove the1702 // node from the tree.1703 if (currentParentIsContainer) {1704 removeChildFromContainer(1705 ((currentParent: any): Container),1706 (node.stateNode: Instance | TextInstance),1707 );1708 } else {1709 removeChild(1710 ((currentParent: any): Instance),1711 (node.stateNode: Instance | TextInstance),1712 );1713 }1714 // Don't visit children because we already visited them.1715 } else if (1716 enableSuspenseServerRenderer &&1717 node.tag === DehydratedFragment1718 ) {1719 if (enableSuspenseCallback) {1720 const hydrationCallbacks = finishedRoot.hydrationCallbacks;1721 if (hydrationCallbacks !== null) {1722 const onDeleted = hydrationCallbacks.onDeleted;1723 if (onDeleted) {1724 onDeleted((node.stateNode: SuspenseInstance));1725 }1726 }1727 }17281729 // Delete the dehydrated suspense boundary and all of its content.1730 if (currentParentIsContainer) {1731 clearSuspenseBoundaryFromContainer(1732 ((currentParent: any): Container),1733 (node.stateNode: SuspenseInstance),1734 );1735 } else {1736 clearSuspenseBoundary(1737 ((currentParent: any): Instance),1738 (node.stateNode: SuspenseInstance),1739 );1740 }1741 } else if (node.tag === HostPortal) {1742 if (node.child !== null) {1743 // When we go into a portal, it becomes the parent to remove from.1744 // We will reassign it back when we pop the portal on the way up.1745 currentParent = node.stateNode.containerInfo;1746 currentParentIsContainer = true;1747 // Visit children because portals might contain host components.1748 node.child.return = node;1749 node = node.child;1750 continue;1751 }1752 } else {1753 commitUnmount(finishedRoot, node, nearestMountedAncestor);1754 // Visit children because we may find more host components below.1755 if (node.child !== null) {1756 node.child.return = node;1757 node = node.child;1758 continue;1759 }1760 }1761 if (node === current) {1762 return;1763 }1764 while (node.sibling === null) {1765 if (node.return === null || node.return === current) {1766 return;1767 }1768 node = node.return;1769 if (node.tag === HostPortal) {1770 // When we go out of the portal, we need to restore the parent.1771 // Since we don't keep a stack of them, we will search for it.1772 currentParentIsValid = false;1773 }1774 }1775 node.sibling.return = node.return;1776 node = node.sibling;1777 }1778}17791780function commitDeletion(1781 finishedRoot: FiberRoot,1782 current: Fiber,1783 nearestMountedAncestor: Fiber,1784): void {1785 if (supportsMutation) {1786 // Recursively delete all host nodes from the parent.1787 // Detach refs and call componentWillUnmount() on the whole subtree.1788 unmountHostComponents(finishedRoot, current, nearestMountedAncestor);1789 } else {1790 // Detach refs and call componentWillUnmount() on the whole subtree.1791 commitNestedUnmounts(finishedRoot, current, nearestMountedAncestor);1792 }17931794 detachFiberMutation(current);1795}17961797function commitWork(current: Fiber | null, finishedWork: Fiber): void {1798 if (!supportsMutation) {1799 switch (finishedWork.tag) {1800 case FunctionComponent:1801 case ForwardRef:1802 case MemoComponent:1803 case SimpleMemoComponent: {1804 // Layout effects are destroyed during the mutation phase so that all1805 // destroy functions for all fibers are called before any create functions.1806 // This prevents sibling component effects from interfering with each other,1807 // e.g. a destroy function in one component should never override a ref set1808 // by a create function in another component during the same commit.1809 if (1810 enableProfilerTimer &&1811 enableProfilerCommitHooks &&1812 finishedWork.mode & ProfileMode1813 ) {1814 try {1815 startLayoutEffectTimer();1816 commitHookEffectListUnmount(1817 HookLayout | HookHasEffect,1818 finishedWork,1819 finishedWork.return,1820 );1821 } finally {1822 recordLayoutEffectDuration(finishedWork);1823 }1824 } else {1825 commitHookEffectListUnmount(1826 HookLayout | HookHasEffect,1827 finishedWork,1828 finishedWork.return,1829 );1830 }1831 return;1832 }1833 case Profiler: {1834 return;1835 }1836 case SuspenseComponent: {1837 commitSuspenseComponent(finishedWork);1838 attachSuspenseRetryListeners(finishedWork);1839 return;1840 }1841 case SuspenseListComponent: {1842 attachSuspenseRetryListeners(finishedWork);1843 return;1844 }1845 case HostRoot: {1846 if (supportsHydration) {1847 const root: FiberRoot = finishedWork.stateNode;1848 if (root.hydrate) {1849 // We've just hydrated. No need to hydrate again.1850 root.hydrate = false;1851 commitHydratedContainer(root.containerInfo);1852 }1853 }1854 break;1855 }1856 case OffscreenComponent:1857 case LegacyHiddenComponent: {1858 return;1859 }1860 }18611862 commitContainer(finishedWork);1863 return;1864 }18651866 switch (finishedWork.tag) {1867 case FunctionComponent:1868 case ForwardRef:1869 case MemoComponent:1870 case SimpleMemoComponent: {1871 // Layout effects are destroyed during the mutation phase so that all1872 // destroy functions for all fibers are called before any create functions.1873 // This prevents sibling component effects from interfering with each other,1874 // e.g. a destroy function in one component should never override a ref set1875 // by a create function in another component during the same commit.1876 if (1877 enableProfilerTimer &&1878 enableProfilerCommitHooks &&1879 finishedWork.mode & ProfileMode1880 ) {1881 try {1882 startLayoutEffectTimer();1883 commitHookEffectListUnmount(1884 HookLayout | HookHasEffect,1885 finishedWork,1886 finishedWork.return,1887 );1888 } finally {1889 recordLayoutEffectDuration(finishedWork);1890 }1891 } else {1892 commitHookEffectListUnmount(1893 HookLayout | HookHasEffect,1894 finishedWork,1895 finishedWork.return,1896 );1897 }1898 return;1899 }1900 case ClassComponent: {1901 return;1902 }1903 case HostComponent: {1904 const instance: Instance = finishedWork.stateNode;1905 if (instance != null) {1906 // Commit the work prepared earlier.1907 const newProps = finishedWork.memoizedProps;1908 // For hydration we reuse the update path but we treat the oldProps1909 // as the newProps. The updatePayload will contain the real change in1910 // this case.1911 const oldProps = current !== null ? current.memoizedProps : newProps;1912 const type = finishedWork.type;1913 // TODO: Type the updateQueue to be specific to host components.1914 const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);1915 finishedWork.updateQueue = null;1916 if (updatePayload !== null) {1917 commitUpdate(1918 instance,1919 updatePayload,1920 type,1921 oldProps,1922 newProps,1923 finishedWork,1924 );1925 }1926 }1927 return;1928 }1929 case HostText: {1930 invariant(1931 finishedWork.stateNode !== null,1932 'This should have a text node initialized. This error is likely ' +1933 'caused by a bug in React. Please file an issue.',1934 );1935 const textInstance: TextInstance = finishedWork.stateNode;1936 const newText: string = finishedWork.memoizedProps;1937 // For hydration we reuse the update path but we treat the oldProps1938 // as the newProps. The updatePayload will contain the real change in1939 // this case.1940 const oldText: string =1941 current !== null ? current.memoizedProps : newText;1942 commitTextUpdate(textInstance, oldText, newText);1943 return;1944 }1945 case HostRoot: {1946 if (supportsHydration) {1947 const root: FiberRoot = finishedWork.stateNode;1948 if (root.hydrate) {1949 // We've just hydrated. No need to hydrate again.1950 root.hydrate = false;1951 commitHydratedContainer(root.containerInfo);1952 }1953 }1954 return;1955 }1956 case Profiler: {1957 return;1958 }1959 case SuspenseComponent: {1960 commitSuspenseComponent(finishedWork);1961 attachSuspenseRetryListeners(finishedWork);1962 return;1963 }1964 case SuspenseListComponent: {1965 attachSuspenseRetryListeners(finishedWork);1966 return;1967 }1968 case IncompleteClassComponent: {1969 return;1970 }1971 case ScopeComponent: {1972 if (enableScopeAPI) {1973 const scopeInstance = finishedWork.stateNode;1974 prepareScopeUpdate(scopeInstance, finishedWork);1975 return;1976 }1977 break;1978 }1979 case OffscreenComponent:1980 case LegacyHiddenComponent: {1981 const newState: OffscreenState | null = finishedWork.memoizedState;1982 const isHidden = newState !== null;1983 hideOrUnhideAllChildren(finishedWork, isHidden);1984 return;1985 }1986 }1987 invariant(1988 false,1989 'This unit of work tag should not have side-effects. This error is ' +1990 'likely caused by a bug in React. Please file an issue.',1991 );1992}19931994function commitSuspenseComponent(finishedWork: Fiber) {1995 const newState: SuspenseState | null = finishedWork.memoizedState;19961997 if (newState !== null) {1998 markCommitTimeOfFallback();19992000 if (supportsMutation) {2001 // Hide the Offscreen component that contains the primary children. TODO:2002 // Ideally, this effect would have been scheduled on the Offscreen fiber2003 // itself. That's how unhiding works: the Offscreen component schedules an2004 // effect on itself. However, in this case, the component didn't complete,2005 // so the fiber was never added to the effect list in the normal path. We2006 // could have appended it to the effect list in the Suspense component's2007 // second pass, but doing it this way is less complicated. This would be2008 // simpler if we got rid of the effect list and traversed the tree, like2009 // we're planning to do.2010 const primaryChildParent: Fiber = (finishedWork.child: any);2011 hideOrUnhideAllChildren(primaryChildParent, true);2012 }2013 }20142015 if (enableSuspenseCallback && newState !== null) {2016 const suspenseCallback = finishedWork.memoizedProps.suspenseCallback;2017 if (typeof suspenseCallback === 'function') {2018 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);2019 if (wakeables !== null) {2020 suspenseCallback(new Set(wakeables));2021 }2022 } else if (__DEV__) {2023 if (suspenseCallback !== undefined) {2024 console.error('Unexpected type for suspenseCallback.');2025 }2026 }2027 }2028}20292030function commitSuspenseHydrationCallbacks(2031 finishedRoot: FiberRoot,2032 finishedWork: Fiber,2033) {2034 if (!supportsHydration) {2035 return;2036 }2037 const newState: SuspenseState | null = finishedWork.memoizedState;2038 if (newState === null) {2039 const current = finishedWork.alternate;2040 if (current !== null) {2041 const prevState: SuspenseState | null = current.memoizedState;2042 if (prevState !== null) {2043 const suspenseInstance = prevState.dehydrated;2044 if (suspenseInstance !== null) {2045 commitHydratedSuspenseInstance(suspenseInstance);2046 if (enableSuspenseCallback) {2047 const hydrationCallbacks = finishedRoot.hydrationCallbacks;2048 if (hydrationCallbacks !== null) {2049 const onHydrated = hydrationCallbacks.onHydrated;2050 if (onHydrated) {2051 onHydrated(suspenseInstance);2052 }2053 }2054 }2055 }2056 }2057 }2058 }2059}20602061function attachSuspenseRetryListeners(finishedWork: Fiber) {2062 // If this boundary just timed out, then it will have a set of wakeables.2063 // For each wakeable, attach a listener so that when it resolves, React2064 // attempts to re-render the boundary in the primary (pre-timeout) state.2065 const wakeables: Set<Wakeable> | null = (finishedWork.updateQueue: any);2066 if (wakeables !== null) {2067 finishedWork.updateQueue = null;2068 let retryCache = finishedWork.stateNode;2069 if (retryCache === null) {2070 retryCache = finishedWork.stateNode = new PossiblyWeakSet();2071 }2072 wakeables.forEach(wakeable => {2073 // Memoize using the boundary fiber to prevent redundant listeners.2074 const retry = resolveRetryWakeable.bind(null, finishedWork, wakeable);2075 if (!retryCache.has(wakeable)) {2076 retryCache.add(wakeable);20772078 if (enableUpdaterTracking) {2079 if (isDevToolsPresent) {2080 if (inProgressLanes !== null && inProgressRoot !== null) {2081 // If we have pending work still, associate the original updaters with it.2082 restorePendingUpdaters(inProgressRoot, inProgressLanes);2083 } else {2084 throw Error(2085 'Expected finished root and lanes to be set. This is a bug in React.',2086 );2087 }2088 }2089 }20902091 wakeable.then(retry, retry);2092 }2093 });2094 }2095}20962097// This function detects when a Suspense boundary goes from visible to hidden.2098// It returns false if the boundary is already hidden.2099// TODO: Use an effect tag.2100export function isSuspenseBoundaryBeingHidden(2101 current: Fiber | null,2102 finishedWork: Fiber,2103): boolean {2104 if (current !== null) {2105 const oldState: SuspenseState | null = current.memoizedState;2106 if (oldState === null || oldState.dehydrated !== null) {2107 const newState: SuspenseState | null = finishedWork.memoizedState;2108 return newState !== null && newState.dehydrated === null;2109 }2110 }2111 return false;2112}21132114function commitResetTextContent(current: Fiber) {2115 if (!supportsMutation) {2116 return;2117 }2118 resetTextContent(current.stateNode);2119}21202121export function commitMutationEffects(2122 root: FiberRoot,2123 firstChild: Fiber,2124 committedLanes: Lanes,2125) {2126 inProgressLanes = committedLanes;2127 inProgressRoot = root;2128 nextEffect = firstChild;21292130 commitMutationEffects_begin(root);21312132 inProgressLanes = null;2133 inProgressRoot = null;2134}21352136function commitMutationEffects_begin(root: FiberRoot) {2137 while (nextEffect !== null) {2138 const fiber = nextEffect;21392140 // TODO: Should wrap this in flags check, too, as optimization2141 const deletions = fiber.deletions;2142 if (deletions !== null) {2143 for (let i = 0; i < deletions.length; i++) {2144 const childToDelete = deletions[i];2145 if (__DEV__) {2146 invokeGuardedCallback(2147 null,2148 commitDeletion,2149 null,2150 root,2151 childToDelete,2152 fiber,2153 );2154 if (hasCaughtError()) {2155 const error = clearCaughtError();2156 captureCommitPhaseError(childToDelete, fiber, error);2157 }2158 } else {2159 try {2160 commitDeletion(root, childToDelete, fiber);2161 } catch (error) {2162 captureCommitPhaseError(childToDelete, fiber, error);2163 }2164 }2165 }2166 }21672168 const child = fiber.child;2169 if ((fiber.subtreeFlags & MutationMask) !== NoFlags && child !== null) {2170 ensureCorrectReturnPointer(child, fiber);2171 nextEffect = child;2172 } else {2173 commitMutationEffects_complete(root);2174 }2175 }2176}21772178function commitMutationEffects_complete(root: FiberRoot) {2179 while (nextEffect !== null) {2180 const fiber = nextEffect;2181 if (__DEV__) {2182 setCurrentDebugFiberInDEV(fiber);2183 invokeGuardedCallback(2184 null,2185 commitMutationEffectsOnFiber,2186 null,2187 fiber,2188 root,2189 );2190 if (hasCaughtError()) {2191 const error = clearCaughtError();2192 captureCommitPhaseError(fiber, fiber.return, error);2193 }2194 resetCurrentDebugFiberInDEV();2195 } else {2196 try {2197 commitMutationEffectsOnFiber(fiber, root);2198 } catch (error) {2199 captureCommitPhaseError(fiber, fiber.return, error);2200 }2201 }22022203 const sibling = fiber.sibling;2204 if (sibling !== null) {2205 ensureCorrectReturnPointer(sibling, fiber.return);2206 nextEffect = sibling;2207 return;2208 }22092210 nextEffect = fiber.return;2211 }2212}22132214function commitMutationEffectsOnFiber(finishedWork: Fiber, root: FiberRoot) {2215 const flags = finishedWork.flags;22162217 if (flags & ContentReset) {2218 commitResetTextContent(finishedWork);2219 }22202221 if (flags & Ref) {2222 const current = finishedWork.alternate;2223 if (current !== null) {2224 commitDetachRef(current);2225 }2226 if (enableScopeAPI) {2227 // TODO: This is a temporary solution that allowed us to transition away2228 // from React Flare on www.2229 if (finishedWork.tag === ScopeComponent) {2230 commitAttachRef(finishedWork);2231 }2232 }2233 }22342235 // The following switch statement is only concerned about placement,2236 // updates, and deletions. To avoid needing to add a case for every possible2237 // bitmap value, we remove the secondary effects from the effect tag and2238 // switch on that value.2239 const primaryFlags = flags & (Placement | Update | Hydrating);2240 outer: switch (primaryFlags) {2241 case Placement: {2242 commitPlacement(finishedWork);2243 // Clear the "placement" from effect tag so that we know that this is2244 // inserted, before any life-cycles like componentDidMount gets called.2245 // TODO: findDOMNode doesn't rely on this any more but isMounted does2246 // and isMounted is deprecated anyway so we should be able to kill this.2247 finishedWork.flags &= ~Placement;2248 break;2249 }2250 case PlacementAndUpdate: {2251 // Placement2252 commitPlacement(finishedWork);2253 // Clear the "placement" from effect tag so that we know that this is2254 // inserted, before any life-cycles like componentDidMount gets called.2255 finishedWork.flags &= ~Placement;22562257 // Update2258 const current = finishedWork.alternate;2259 commitWork(current, finishedWork);2260 break;2261 }2262 case Hydrating: {2263 finishedWork.flags &= ~Hydrating;2264 break;2265 }2266 case HydratingAndUpdate: {2267 finishedWork.flags &= ~Hydrating;22682269 // Update2270 const current = finishedWork.alternate;2271 commitWork(current, finishedWork);2272 break;2273 }2274 case Update: {2275 const current = finishedWork.alternate;2276 commitWork(current, finishedWork);2277 break;2278 }2279 }2280}22812282export function commitLayoutEffects(2283 finishedWork: Fiber,2284 root: FiberRoot,2285 committedLanes: Lanes,2286): void {2287 inProgressLanes = committedLanes;2288 inProgressRoot = root;2289 nextEffect = finishedWork;22902291 commitLayoutEffects_begin(finishedWork, root, committedLanes);22922293 inProgressLanes = null;2294 inProgressRoot = null;2295}22962297function commitLayoutEffects_begin(2298 subtreeRoot: Fiber,2299 root: FiberRoot,2300 committedLanes: Lanes,2301) {2302 // Suspense layout effects semantics don't change for legacy roots.2303 const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;23042305 while (nextEffect !== null) {2306 const fiber = nextEffect;2307 const firstChild = fiber.child;23082309 if (2310 enableSuspenseLayoutEffectSemantics &&2311 fiber.tag === OffscreenComponent &&2312 isModernRoot2313 ) {2314 // Keep track of the current Offscreen stack's state.2315 const isHidden = fiber.memoizedState !== null;2316 const newOffscreenSubtreeIsHidden = isHidden || offscreenSubtreeIsHidden;2317 if (newOffscreenSubtreeIsHidden) {2318 // The Offscreen tree is hidden. Skip over its layout effects.2319 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2320 continue;2321 } else {2322 if ((fiber.subtreeFlags & LayoutMask) !== NoFlags) {2323 const current = fiber.alternate;2324 const wasHidden = current !== null && current.memoizedState !== null;2325 const newOffscreenSubtreeWasHidden =2326 wasHidden || offscreenSubtreeWasHidden;2327 const prevOffscreenSubtreeIsHidden = offscreenSubtreeIsHidden;2328 const prevOffscreenSubtreeWasHidden = offscreenSubtreeWasHidden;23292330 // Traverse the Offscreen subtree with the current Offscreen as the root.2331 offscreenSubtreeIsHidden = newOffscreenSubtreeIsHidden;2332 offscreenSubtreeWasHidden = newOffscreenSubtreeWasHidden;2333 let child = firstChild;2334 while (child !== null) {2335 nextEffect = child;2336 commitLayoutEffects_begin(2337 child, // New root; bubble back up to here and stop.2338 root,2339 committedLanes,2340 );2341 child = child.sibling;2342 }23432344 // Restore Offscreen state and resume in our-progress traversal.2345 nextEffect = fiber;2346 offscreenSubtreeIsHidden = prevOffscreenSubtreeIsHidden;2347 offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden;2348 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);23492350 continue;2351 }2352 }2353 }23542355 if ((fiber.subtreeFlags & LayoutMask) !== NoFlags && firstChild !== null) {2356 ensureCorrectReturnPointer(firstChild, fiber);2357 nextEffect = firstChild;2358 } else {2359 if (enableSuspenseLayoutEffectSemantics && isModernRoot) {2360 const visibilityChanged =2361 !offscreenSubtreeIsHidden && offscreenSubtreeWasHidden;23622363 // TODO (Offscreen) Also check: subtreeFlags & LayoutStatic2364 if (visibilityChanged && firstChild !== null) {2365 // We've just shown or hidden a Offscreen tree that contains layout effects.2366 // We only enter this code path for subtrees that are updated,2367 // because newly mounted ones would pass the LayoutMask check above.2368 ensureCorrectReturnPointer(firstChild, fiber);2369 nextEffect = firstChild;2370 continue;2371 }2372 }23732374 commitLayoutMountEffects_complete(subtreeRoot, root, committedLanes);2375 }2376 }2377}23782379function commitLayoutMountEffects_complete(2380 subtreeRoot: Fiber,2381 root: FiberRoot,2382 committedLanes: Lanes,2383) {2384 // Suspense layout effects semantics don't change for legacy roots.2385 const isModernRoot = (subtreeRoot.mode & ConcurrentMode) !== NoMode;23862387 while (nextEffect !== null) {2388 const fiber = nextEffect;23892390 if (2391 enableSuspenseLayoutEffectSemantics &&2392 isModernRoot &&2393 offscreenSubtreeWasHidden &&2394 !offscreenSubtreeIsHidden2395 ) {2396 // Inside of an Offscreen subtree that changed visibility during this commit.2397 // If this subtree was hidden, layout effects will have already been destroyed (during mutation phase)2398 // but if it was just shown, we need to (re)create the effects now.2399 // TODO (Offscreen) Check: flags & LayoutStatic2400 switch (fiber.tag) {2401 case FunctionComponent:2402 case ForwardRef:2403 case SimpleMemoComponent: {2404 if (2405 enableProfilerTimer &&2406 enableProfilerCommitHooks &&2407 fiber.mode & ProfileMode2408 ) {2409 try {2410 startLayoutEffectTimer();2411 safelyCallCommitHookLayoutEffectListMount(fiber, fiber.return);2412 } finally {2413 recordLayoutEffectDuration(fiber);2414 }2415 } else {2416 safelyCallCommitHookLayoutEffectListMount(fiber, fiber.return);2417 }2418 break;2419 }2420 case ClassComponent: {2421 const instance = fiber.stateNode;2422 if (typeof instance.componentDidMount === 'function') {2423 safelyCallComponentDidMount(fiber, fiber.return, instance);2424 }2425 break;2426 }2427 }24282429 // TODO (Offscreen) Check flags & RefStatic2430 switch (fiber.tag) {2431 case ClassComponent:2432 case HostComponent:2433 safelyAttachRef(fiber, fiber.return);2434 break;2435 }2436 } else if ((fiber.flags & LayoutMask) !== NoFlags) {2437 const current = fiber.alternate;2438 if (__DEV__) {2439 setCurrentDebugFiberInDEV(fiber);2440 invokeGuardedCallback(2441 null,2442 commitLayoutEffectOnFiber,2443 null,2444 root,2445 current,2446 fiber,2447 committedLanes,2448 );2449 if (hasCaughtError()) {2450 const error = clearCaughtError();2451 captureCommitPhaseError(fiber, fiber.return, error);2452 }2453 resetCurrentDebugFiberInDEV();2454 } else {2455 try {2456 commitLayoutEffectOnFiber(root, current, fiber, committedLanes);2457 } catch (error) {2458 captureCommitPhaseError(fiber, fiber.return, error);2459 }2460 }2461 }24622463 if (fiber === subtreeRoot) {2464 nextEffect = null;2465 return;2466 }24672468 const sibling = fiber.sibling;2469 if (sibling !== null) {2470 ensureCorrectReturnPointer(sibling, fiber.return);2471 nextEffect = sibling;2472 return;2473 }24742475 nextEffect = fiber.return;2476 }2477}24782479export function commitPassiveMountEffects(2480 root: FiberRoot,2481 finishedWork: Fiber,2482): void {2483 nextEffect = finishedWork;2484 commitPassiveMountEffects_begin(finishedWork, root);2485}24862487function commitPassiveMountEffects_begin(subtreeRoot: Fiber, root: FiberRoot) {2488 while (nextEffect !== null) {2489 const fiber = nextEffect;2490 const firstChild = fiber.child;2491 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && firstChild !== null) {2492 ensureCorrectReturnPointer(firstChild, fiber);2493 nextEffect = firstChild;2494 } else {2495 commitPassiveMountEffects_complete(subtreeRoot, root);2496 }2497 }2498}24992500function commitPassiveMountEffects_complete(2501 subtreeRoot: Fiber,2502 root: FiberRoot,2503) {2504 while (nextEffect !== null) {2505 const fiber = nextEffect;2506 if ((fiber.flags & Passive) !== NoFlags) {2507 if (__DEV__) {2508 setCurrentDebugFiberInDEV(fiber);2509 invokeGuardedCallback(2510 null,2511 commitPassiveMountOnFiber,2512 null,2513 root,2514 fiber,2515 );2516 if (hasCaughtError()) {2517 const error = clearCaughtError();2518 captureCommitPhaseError(fiber, fiber.return, error);2519 }2520 resetCurrentDebugFiberInDEV();2521 } else {2522 try {2523 commitPassiveMountOnFiber(root, fiber);2524 } catch (error) {2525 captureCommitPhaseError(fiber, fiber.return, error);2526 }2527 }2528 }25292530 if (fiber === subtreeRoot) {2531 nextEffect = null;2532 return;2533 }25342535 const sibling = fiber.sibling;2536 if (sibling !== null) {2537 ensureCorrectReturnPointer(sibling, fiber.return);2538 nextEffect = sibling;2539 return;2540 }25412542 nextEffect = fiber.return;2543 }2544}25452546function commitPassiveMountOnFiber(2547 finishedRoot: FiberRoot,2548 finishedWork: Fiber,2549): void {2550 switch (finishedWork.tag) {2551 case FunctionComponent:2552 case ForwardRef:2553 case SimpleMemoComponent: {2554 if (2555 enableProfilerTimer &&2556 enableProfilerCommitHooks &&2557 finishedWork.mode & ProfileMode2558 ) {2559 startPassiveEffectTimer();2560 try {2561 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2562 } finally {2563 recordPassiveEffectDuration(finishedWork);2564 }2565 } else {2566 commitHookEffectListMount(HookPassive | HookHasEffect, finishedWork);2567 }2568 break;2569 }2570 }2571}25722573export function commitPassiveUnmountEffects(firstChild: Fiber): void {2574 nextEffect = firstChild;2575 commitPassiveUnmountEffects_begin();2576}25772578function commitPassiveUnmountEffects_begin() {2579 while (nextEffect !== null) {2580 const fiber = nextEffect;2581 const child = fiber.child;25822583 if ((nextEffect.flags & ChildDeletion) !== NoFlags) {2584 const deletions = fiber.deletions;2585 if (deletions !== null) {2586 for (let i = 0; i < deletions.length; i++) {2587 const fiberToDelete = deletions[i];2588 nextEffect = fiberToDelete;2589 commitPassiveUnmountEffectsInsideOfDeletedTree_begin(2590 fiberToDelete,2591 fiber,2592 );2593 }25942595 if (deletedTreeCleanUpLevel >= 1) {2596 // A fiber was deleted from this parent fiber, but it's still part of2597 // the previous (alternate) parent fiber's list of children. Because2598 // children are a linked list, an earlier sibling that's still alive2599 // will be connected to the deleted fiber via its `alternate`:2600 //2601 // live fiber2602 // --alternate--> previous live fiber2603 // --sibling--> deleted fiber2604 //2605 // We can't disconnect `alternate` on nodes that haven't been deleted2606 // yet, but we can disconnect the `sibling` and `child` pointers.2607 const previousFiber = fiber.alternate;2608 if (previousFiber !== null) {2609 let detachedChild = previousFiber.child;2610 if (detachedChild !== null) {2611 previousFiber.child = null;2612 do {2613 const detachedSibling = detachedChild.sibling;2614 detachedChild.sibling = null;2615 detachedChild = detachedSibling;2616 } while (detachedChild !== null);2617 }2618 }2619 }26202621 nextEffect = fiber;2622 }2623 }26242625 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && child !== null) {2626 ensureCorrectReturnPointer(child, fiber);2627 nextEffect = child;2628 } else {2629 commitPassiveUnmountEffects_complete();2630 }2631 }2632}26332634function commitPassiveUnmountEffects_complete() {2635 while (nextEffect !== null) {2636 const fiber = nextEffect;2637 if ((fiber.flags & Passive) !== NoFlags) {2638 setCurrentDebugFiberInDEV(fiber);2639 commitPassiveUnmountOnFiber(fiber);2640 resetCurrentDebugFiberInDEV();2641 }26422643 const sibling = fiber.sibling;2644 if (sibling !== null) {2645 ensureCorrectReturnPointer(sibling, fiber.return);2646 nextEffect = sibling;2647 return;2648 }26492650 nextEffect = fiber.return;2651 }2652}26532654function commitPassiveUnmountOnFiber(finishedWork: Fiber): void {2655 switch (finishedWork.tag) {2656 case FunctionComponent:2657 case ForwardRef:2658 case SimpleMemoComponent: {2659 if (2660 enableProfilerTimer &&2661 enableProfilerCommitHooks &&2662 finishedWork.mode & ProfileMode2663 ) {2664 startPassiveEffectTimer();2665 commitHookEffectListUnmount(2666 HookPassive | HookHasEffect,2667 finishedWork,2668 finishedWork.return,2669 );2670 recordPassiveEffectDuration(finishedWork);2671 } else {2672 commitHookEffectListUnmount(2673 HookPassive | HookHasEffect,2674 finishedWork,2675 finishedWork.return,2676 );2677 }2678 break;2679 }2680 }2681}26822683function commitPassiveUnmountEffectsInsideOfDeletedTree_begin(2684 deletedSubtreeRoot: Fiber,2685 nearestMountedAncestor: Fiber | null,2686) {2687 while (nextEffect !== null) {2688 const fiber = nextEffect;26892690 // Deletion effects fire in parent -> child order2691 // TODO: Check if fiber has a PassiveStatic flag2692 setCurrentDebugFiberInDEV(fiber);2693 commitPassiveUnmountInsideDeletedTreeOnFiber(fiber, nearestMountedAncestor);2694 resetCurrentDebugFiberInDEV();26952696 const child = fiber.child;2697 // TODO: Only traverse subtree if it has a PassiveStatic flag. (But, if we2698 // do this, still need to handle `deletedTreeCleanUpLevel` correctly.)2699 if (child !== null) {2700 ensureCorrectReturnPointer(child, fiber);2701 nextEffect = child;2702 } else {2703 commitPassiveUnmountEffectsInsideOfDeletedTree_complete(2704 deletedSubtreeRoot,2705 );2706 }2707 }2708}27092710function commitPassiveUnmountEffectsInsideOfDeletedTree_complete(2711 deletedSubtreeRoot: Fiber,2712) {2713 while (nextEffect !== null) {2714 const fiber = nextEffect;2715 const sibling = fiber.sibling;2716 const returnFiber = fiber.return;27172718 if (deletedTreeCleanUpLevel >= 2) {2719 // Recursively traverse the entire deleted tree and clean up fiber fields.2720 // This is more aggressive than ideal, and the long term goal is to only2721 // have to detach the deleted tree at the root.2722 detachFiberAfterEffects(fiber);2723 if (fiber === deletedSubtreeRoot) {2724 nextEffect = null;2725 return;2726 }2727 } else {2728 // This is the default branch (level 0). We do not recursively clear all2729 // the fiber fields. Only the root of the deleted subtree.2730 if (fiber === deletedSubtreeRoot) {2731 detachFiberAfterEffects(fiber);2732 nextEffect = null;2733 return;2734 }2735 }27362737 if (sibling !== null) {2738 ensureCorrectReturnPointer(sibling, returnFiber);2739 nextEffect = sibling;2740 return;2741 }27422743 nextEffect = returnFiber;2744 }2745}
...
ReactFiberWorkLoop.js
Source:ReactFiberWorkLoop.js
...237 while (effect !== null) {238 const nextNextEffect = effect.nextEffect;239 effect.nextEffect = null;240 if (effect.flags & Deletion) {241 detachFiberAfterEffects(effect);242 }243 effect = nextNextEffect;244 }245 executionContext = prevExecutionContext;246 flushSyncCallbackQueue();247 nestedPassiveUpdateCount =248 rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;249 return true;250};251const flushPassiveEffects = () => {252 if (pendingPassiveEffectsRenderPriority !== NoSchedulerPriority) {253 const priorityLevel =254 pendingPassiveEffectsRenderPriority > NormalSchedulerPriority255 ? NormalSchedulerPriority256 : pendingPassiveEffectsRenderPriority;257 pendingPassiveEffectsRenderPriority = NoSchedulerPriority;258 return runWithPriority(priorityLevel, flushPassiveEffectsImpl);259 }260 return false;261};262const pushDispatcher = () => {263 const prevDispatcher = ReactCurrentDispatcher.current;264 ReactCurrentDispatcher.current = ContextOnlyDispatcher;265 if (prevDispatcher === null) {266 return ContextOnlyDispatcher;267 } else {268 return prevDispatcher;269 }270};271const popDispatcher = (prevDispatcher) => {272 ReactCurrentDispatcher.current = prevDispatcher;273};274const prepareFreshStack = (root, lanes) => {275 root.finishedWork = null;276 root.finishedLanes = NoLanes;277 const timeoutHandle = root.timeoutHandle;278 if (timeoutHandle !== noTimeout) {279 root.timeoutHandle = noTimeout;280 clearTimeout(timeoutHandle);281 }282 if (workInProgress !== null) {283 let interruptedWork = workInProgress.return;284 while (interruptedWork !== null) {285 unwindInterruptedWork(interruptedWork);286 interruptedWork = interruptedWork.return;287 }288 }289 workInProgressRoot = root;290 workInProgress = createWorkInProgress(root.current, null);291 workInProgressRootRenderLanes =292 subtreeRenderLanes =293 workInProgressRootIncludedLanes =294 lanes;295 workInProgressRootExitStatus = RootIncomplete;296 workInProgressRootFatalError = null;297 workInProgressRootSkippedLanes = NoLanes;298 workInProgressRootUpdatedLanes = NoLanes;299 workInProgressRootPingedLanes = NoLanes;300};301const resetChildLanes = (completedWork) => {302 if (303 (completedWork.tag === LegacyHiddenComponent ||304 completedWork.tag === OffscreenComponent) &&305 completedWork.memoizedState !== null &&306 !includesSomeLane(subtreeRenderLanes, OffscreenLane) &&307 (completedWork.mode & ConcurrentMode) !== NoLanes308 )309 return;310 let newChildLanes = NoLanes;311 let child = completedWork.child;312 while (child !== null) {313 newChildLanes = mergeLanes(314 newChildLanes,315 mergeLanes(child.lanes, child.childLanes)316 );317 child = child.sibling;318 }319 completedWork.childLanes = newChildLanes;320};321const completeUnitOfWork = (unitOfWork) => {322 let completedWork = unitOfWork;323 do {324 const current = completedWork.alternate;325 const returnFiber = completedWork.return;326 console.log(completedWork, '------completeUnitOfWork:completedWork');327 if ((completedWork.flags & Incomplete) === NoFlags) {328 const next = completeWork(current, completedWork, subtreeRenderLanes);329 console.log(next, '------completeUnitOfWork:next');330 if (next !== null) {331 workInProgress = next;332 return;333 }334 resetChildLanes(completedWork);335 if (336 returnFiber !== null &&337 (returnFiber.flags & Incomplete) === NoFlags338 ) {339 if (returnFiber.firstEffect === null) {340 returnFiber.firstEffect = completedWork.firstEffect;341 }342 if (completedWork.lastEffect !== null) {343 if (returnFiber.lastEffect !== null) {344 returnFiber.lastEffect.nextEffect = completedWork.firstEffect;345 }346 returnFiber.lastEffect = completedWork.lastEffect;347 }348 const flags = completedWork.flags;349 if (flags > PerformedWork) {350 if (returnFiber.lastEffect !== null) {351 returnFiber.lastEffect.nextEffect = completedWork;352 } else {353 returnFiber.firstEffect = completedWork;354 }355 returnFiber.lastEffect = completedWork;356 }357 }358 } else {359 const next = unwindWork(completedWork, subtreeRenderLanes);360 if (next !== null) {361 next.flags &= HostEffectMask;362 workInProgress = next;363 return;364 }365 if (returnFiber !== null) {366 returnFiber.firstEffect = returnFiber.lastEffect = null;367 returnFiber.flags |= Incomplete;368 }369 }370 const siblingFiber = completedWork.sibling;371 if (siblingFiber !== null) {372 workInProgress = siblingFiber;373 return;374 }375 completedWork = returnFiber;376 workInProgress = completedWork;377 } while (completedWork !== null);378 if (workInProgressRootExitStatus === RootIncomplete) {379 workInProgressRootExitStatus = RootCompleted;380 }381};382const performUnitOfWork = (unitOfWork) => {383 const current = unitOfWork.alternate;384 console.log({ ...unitOfWork }, '--------performUnitOfWork(workInProgress)');385 const next = beginWork(current, unitOfWork, subtreeRenderLanes);386 console.log({ ...next }, '--------performUnitOfWork:next');387 unitOfWork.memoizedProps = unitOfWork.pendingProps;388 if (next === null) {389 completeUnitOfWork(unitOfWork);390 } else {391 workInProgress = next;392 }393 ReactCurrentOwner.current = null;394};395const workLoopSync = () => {396 while (workInProgress !== null) {397 performUnitOfWork(workInProgress);398 }399};400const commitBeforeMutationEffects = () => {401 while (nextEffect !== null) {402 const current = nextEffect.alternate;403 const flags = nextEffect.flags;404 if ((flags & Snapshot) !== NoFlags) {405 commitBeforeMutationLifeCycles(current, nextEffect);406 }407 if ((flags & Passive) !== NoFlags) {408 if (!rootDoesHavePassiveEffects) {409 rootDoesHavePassiveEffects = true;410 scheduleCallback(NormalSchedulerPriority, () => {411 flushPassiveEffects();412 return null;413 });414 }415 }416 nextEffect = nextEffect.nextEffect;417 }418};419const commitMutationEffects = (root, renderPriorityLevel) => {420 while (nextEffect !== null) {421 const flags = nextEffect.flags;422 if (flags & ContentReset) {423 commitResetTextContent(nextEffect);424 }425 if (flags & Ref) {426 const current = nextEffect.alternate;427 if (current !== null) {428 commitDetachRef(current);429 }430 }431 const primaryFlags = flags & (Placement | Update | Deletion | Hydrating);432 console.log(primaryFlags, '------commitMutationEffects:primaryFlags');433 switch (primaryFlags) {434 case Placement: {435 commitPlacement(nextEffect);436 nextEffect.flags &= ~Placement;437 break;438 }439 case PlacementAndUpdate: {440 commitPlacement(nextEffect);441 nextEffect.flags &= ~Placement;442 const current = nextEffect.alternate;443 commitWork(current, nextEffect);444 break;445 }446 case Hydrating: {447 nextEffect.flags &= ~Hydrating;448 break;449 }450 case HydratingAndUpdate: {451 nextEffect.flags &= ~Hydrating;452 const current = nextEffect.alternate;453 commitWork(current, nextEffect);454 break;455 }456 case Update: {457 const current = nextEffect.alternate;458 commitWork(current, nextEffect);459 break;460 }461 case Deletion: {462 commitDeletion(root, nextEffect, renderPriorityLevel);463 break;464 }465 }466 nextEffect = nextEffect.nextEffect;467 }468};469const commitLayoutEffects = (root, committedLanes) => {};470const commitRootImpl = (root, renderPriorityLevel) => {471 do {472 flushPassiveEffects();473 } while (rootWithPendingPassiveEffects !== null);474 console.log(executionContext, '------commitRootImpl:executionContext');475 invariant(476 (executionContext & (RenderContext | CommitContext)) === NoContext,477 'Should not already be working.'478 );479 const finishedWork = root.finishedWork;480 const lanes = root.finishedLanes;481 if (finishedWork === null) return null;482 root.finishedWork = null;483 root.finishedLanes = NoLanes;484 invariant(485 finishedWork !== root.current,486 'Cannot commit the same tree as before. This error is likely caused by ' +487 'a bug in React. Please file an issue.'488 );489 root.callbackNode = null;490 let remainingLanes = mergeLanes(finishedWork.lanes, finishedWork.childLanes);491 markRootFinished(root, remainingLanes);492 if (rootsWithPendingDiscreteUpdates !== null) {493 if (494 !hasDiscreteLanes(remainingLanes) &&495 rootsWithPendingDiscreteUpdates.has(root)496 ) {497 rootsWithPendingDiscreteUpdates.delete(root);498 }499 }500 if (root === workInProgressRoot) {501 workInProgressRoot = null;502 workInProgress = null;503 workInProgressRootRenderLanes = NoLanes;504 }505 let firstEffect;506 if (finishedWork.flags > PerformedWork) {507 if (finishedWork.lastEffect !== null) {508 finishedWork.lastEffect.nextEffect = finishedWork;509 firstEffect = finishedWork.firstEffect;510 } else {511 firstEffect = finishedWork;512 }513 } else {514 firstEffect = finishedWork.firstEffect;515 }516 if (firstEffect !== null) {517 const prevExecutionContext = executionContext;518 executionContext |= CommitContext;519 ReactCurrentOwner.current = null;520 prepareForCommit(root.containerInfo);521 nextEffect = firstEffect;522 do {523 try {524 commitBeforeMutationEffects();525 } catch (error) {526 invariant(nextEffect !== null, 'Should be working on an effect.');527 // captureCommitPhaseError(nextEffect, error);528 nextEffect = nextEffect.nextEffect;529 }530 } while (nextEffect !== null);531 nextEffect = firstEffect;532 console.log({ ...nextEffect }, '------commitMutationEffects>nextEffect');533 do {534 try {535 commitMutationEffects(root, renderPriorityLevel);536 } catch (error) {537 invariant(nextEffect !== null, 'Should be working on an effect.');538 // captureCommitPhaseError(nextEffect, error);539 nextEffect = nextEffect.nextEffect;540 }541 } while (nextEffect !== null);542 resetAfterCommit(root.containerInfo);543 root.current = finishedWork;544 nextEffect = firstEffect;545 // do {546 // try {547 // commitLayoutEffects(root, lanes);548 // } catch (error) {549 // invariant(nextEffect !== null, 'Should be working on an effect.');550 // nextEffect = nextEffect.nextEffect;551 // }552 // } while (nextEffect !== null);553 nextEffect = null;554 requestPaint();555 executionContext = prevExecutionContext;556 } else {557 root.current = finishedWork;558 }559 const rootDidHavePassiveEffects = rootDoesHavePassiveEffects;560 if (rootDoesHavePassiveEffects) {561 rootDoesHavePassiveEffects = false;562 rootWithPendingPassiveEffects = root;563 pendingPassiveEffectsLanes = lanes;564 pendingPassiveEffectsRenderPriority = renderPriorityLevel;565 } else {566 nextEffect = firstEffect;567 while (nextEffect !== null) {568 const nextNextEffect = nextEffect.nextEffect;569 nextEffect.nextEffect = null;570 if (nextEffect.flags & Deletion) {571 detachFiberAfterEffects(nextEffect);572 }573 nextEffect = nextNextEffect;574 }575 }576 remainingLanes = root.pendingLanes;577 legacyErrorBoundariesThatAlreadyFailed = null;578 if (remainingLanes === SyncLane) {579 if (root === rootWithNestedUpdates) {580 nestedUpdateCount++;581 } else {582 nestedUpdateCount = 0;583 rootWithNestedUpdates = root;584 }585 } else {...
FiberCommitWork.js
Source:FiberCommitWork.js
...349 const fiber = nextEffect;350 const sibling = fiber.sibling;351 const returnFiber = fiber.return;352 if (fiber === deletedSubtreeRoot){353 detachFiberAfterEffects(fiber);354 nextEffect = null;355 return;356 }357 if (sibling !== null){358 nextEffect = sibling;359 return;360 }361 nextEffect = returnFiber;362 }363}364function commitPassiveUnmountEffectsInDelTreeOnFiber(365 current, nearestMountedAncestor366){367 switch(current.tag){368 case FunctionComponent:{369 commitHookEffectListUnmount(370 HookPassive,371 current,372 nearestMountedAncestor373 );374 break;375 }376 }377}378function commitUnmount(finishedRoot, current, nearestMountedAncestor){379 switch(current.tag){380 case FunctionComponent:381 case HostComponent:382 return;383 }384}385function commitNestedUnmounts(finishedRoot, root, nearestMountedAncestor){386 let node = root;387 while(true){388 commitUnmount(finishedRoot, node, nearestMountedAncestor);389 if(node.child !== null){390 node.child.return = node;391 node = node.child;392 continue;393 }394 if (node === root){395 return;396 }397 while (node.sibling === null){398 if (node.return === null || node.return === root){399 return;400 }401 node = node.return;402 }403 node.sibling.return = node.return;404 node = node.sibling;405 }406}407function detachFiberMutation(fiber){408 const alternate = fiber.alternate;409 if (alternate !== null){410 alternate.return = null;411 }412 fiber.return = null;413}414function detachFiberAfterEffects(fiber){415 const alternate = fiber.alternate;416 if (alternate !== null){417 fiber.alternate = null;418 detachFiberAfterEffects(alternate);419 }420 fiber.child = null;421 fiber.deletions = null;422 fiber.sibling = null;423 if (fiber.tag === HostComponent){424 if(fiber.stateNode !== null){425 detachDeletedInstance(fiber.stateNode);426 }427 }428 fiber.stateNode = null;429}430function toggleAllChildren(finishedWork, isHidden){431 let hostSubtreeRoot = null;432 let node = finishedWork;...
ReactFiberCommitWork.js
Source:ReactFiberCommitWork.js
...19 fiber20 );21 // Now that passive effects have been processed, it's safe to detach lingering pointers.22 const alternate = fiberToDelete.alternate;23 detachFiberAfterEffects(fiberToDelete);24 if (alternate !== null) {25 detachFiberAfterEffects(alternate);26 }27 }28 nextEffect = fiber;29 }30 }31 if ((fiber.subtreeFlags & PassiveMask) !== NoFlags && child !== null) {32 ensureCorrectReturnPointer(child, fiber);33 nextEffect = child;34 } else {35 commitPassiveUnmountEffects_complete();36 }37 }38}39function commitPassiveUnmountEffects_complete() {...
Using AI Code Generation
1const { detachFiberAfterEffects } = require('playwright/lib/server/supplements/recorder/recorderSupplement.js');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch({ headless: false });5 const context = await browser.newContext();6 const page = await context.newPage();7 await detachFiberAfterEffects(page);8 await page.screenshot({ path: 'example.png' });9 await browser.close();10})();11const { chromium } = require('playwright');12describe('My test', () => {13 it('should work', async () => {14 const browser = await chromium.launch({ headless: false });15 const context = await browser.newContext();16 const page = await context.newPage();17 await page.screenshot({ path: 'example.png' });18 await browser.close();19 });20});
Using AI Code Generation
1const { chromium } = require('playwright');2const { detachFiberAfterEffects } = require('playwright/lib/server/fiberDetacher');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 await page.screenshot({ path: 'example.png' });7 await browser.close();8 detachFiberAfterEffects();9})();
Using AI Code Generation
1const { detachFiberAfterEffects } = require('@playwright/test/lib/server/fiber');2const { test } = require('@playwright/test');3test('test', async ({ page }) => {4 await detachFiberAfterEffects();5 await page.waitForSelector('text=Playwright is a Node.js library to automate');6});7 0 passed (1s)
Using AI Code Generation
1const { chromium } = require('playwright');2const { attachFiber, detachFiberAfterEffects } = require('playwright/lib/internal/fiber');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 attachFiber(page);8 await page.click('text=Get started');9 await detachFiberAfterEffects();10 await page.waitForTimeout(3000);11 await browser.close();12})();13const { chromium } = require('playwright');14const { attachFiber, detachFiberAfterEffects } = require('playwright/lib/internal/fiber');15describe('My test', () => {16 it('should work', async () => {17 const browser = await chromium.launch();18 const context = await browser.newContext();19 const page = await context.newPage();20 attachFiber(page);21 await page.click('text=Get started');22 await detachFiberAfterEffects();23 await page.waitForTimeout(3000);24 await browser.close();25 });26});27const { chromium } = require('playwright');28const { attachFiber, detachFiberAfterEffects } = require('playwright/lib/internal/fiber');29(async () => {30 const browser = await chromium.launch();31 const context = await browser.newContext();32 const page = await context.newPage();33 attachFiber(page);34 await page.click('text=Get started');35 await detachFiberAfterEffects();36 await page.waitForTimeout(3000);37 await browser.close();38})();
Using AI Code Generation
1const { detachFiberAfterEffects } = require("playwright/lib/server/fiber");2const { chromium } = require("playwright");3const { expect } = require("chai");4(async () => {5 const browser = await chromium.launch();6 const context = await browser.newContext();7 const page = await context.newPage();
Using AI Code Generation
1const playwright = require('playwright');2(async () => {3 const browser = await playwright.chromium.launch({4 });5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.evaluate(() => {8 window.detachFiberAfterEffects();9 for (let i = 0; i < 1000000000; i++) {}10 });11 await page.screenshot({ path: `screenshot.png` });12 await browser.close();13})();14const playwright = require('playwright');15(async () => {16 const browser = await playwright.chromium.launch({17 });18 const context = await browser.newContext();19 const page = await context.newPage();20 await page.evaluate(() => {21 window.attachFiberBeforeEffects();22 for (let i = 0; i < 1000000000; i++) {}23 });24 await page.screenshot({ path: `screenshot.png` });25 await browser.close();26})();27const playwright = require('playwright');28(async () => {29 const browser = await playwright.chromium.launch({
Using AI Code Generation
1const { detachFiberAfterEffects } = require('playwright/lib/internal/inspector/inspector');2await detachFiberAfterEffects();3const { detachFiberAfterEffects } = require('playwright/lib/internal/inspector/inspector');4await detachFiberAfterEffects();5const { detachFiberAfterEffects } = require('playwright/lib/internal/inspector/inspector');6await detachFiberAfterEffects();7const { detachFiberAfterEffects } = require('playwright/lib/internal/inspector/inspector');8await detachFiberAfterEffects();9const { detachFiberAfterEffects } = require('playwright/lib/internal/inspector/inspector');10await detachFiberAfterEffects();11const { detachFiberAfterEffects } = require('playwright/lib/internal/inspector/inspector');12await detachFiberAfterEffects();13const { detachFiberAfterEffects } = require('playwright/lib/internal/inspector/inspector');14await detachFiberAfterEffects();15const { detachFiberAfterEffects } = require('playwright/lib/internal/inspector/inspector');
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!