How to use detachFiberAfterEffects method in Playwright Internal

Best JavaScript code snippet using playwright-internal

ReactFiberCommitWork.old.js

Source:ReactFiberCommitWork.old.js Github

copy

Full Screen

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

Full Screen

Full Screen

ReactFiberCommitWork.new.js

Source:ReactFiberCommitWork.new.js Github

copy

Full Screen

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

Full Screen

Full Screen

ReactFiberWorkLoop.js

Source:ReactFiberWorkLoop.js Github

copy

Full Screen

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

Full Screen

Full Screen

FiberCommitWork.js

Source:FiberCommitWork.js Github

copy

Full Screen

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

Full Screen

Full Screen

ReactFiberCommitWork.js

Source:ReactFiberCommitWork.js Github

copy

Full Screen

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

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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)

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

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

Run Playwright Internal automation tests on LambdaTest cloud grid

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

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful