@samitouri / QOS-React-2 / commits / 12d7a9ad70

Combine commitWork into single switch statement

commitWork is forked into a separate implementation for mutation mode (DOM) and persistent mode (React Native). But unlike when it was first introduced, there's more overlap than differences between the forks, mainly because we've added new types of fibers. So this joins the two forks and adds more local branches where the behavior actually diverges: host nodes, host containers, and portals.

Andrew Clark committed Apr 7, 2022 at 19:00 UTC 12d7a9ad7082106102b7dd9fec4c75abafe1c2a8
2 files changed +110 -294
packages/react-reconciler/src/ReactFiberCommitWork.new.js
+55 -147
@@ -1481,36 +1481,6 @@ function emptyPortalContainer(current: Fiber) {
1481 replaceContainerChildren(containerInfo, emptyChildSet);
1482 }
1483
1484 -function commitContainer(finishedWork: Fiber) {
1485 - if (!supportsPersistence) {
1486 - return;
1487 - }
1488 -
1489 - switch (finishedWork.tag) {
1490 - case ClassComponent:
1491 - case HostComponent:
1492 - case HostText: {
1493 - return;
1494 - }
1495 - case HostRoot:
1496 - case HostPortal: {
1497 - const portalOrRoot: {
1498 - containerInfo: Container,
1499 - pendingChildren: ChildSet,
1500 - ...
1501 - } = finishedWork.stateNode;
1502 - const {containerInfo, pendingChildren} = portalOrRoot;
1503 - replaceContainerChildren(containerInfo, pendingChildren);
1504 - return;
1505 - }
1506 - }
1507 -
1508 - throw new Error(
1509 - 'This unit of work tag should not have side-effects. This error is ' +
1510 - 'likely caused by a bug in React. Please file an issue.',
1511 - );
1512 -}
1513 -
1484 function getHostParentFiber(fiber: Fiber): Fiber {
1485 let parent = fiber.return;
1486 while (parent !== null) {
@@ -1830,87 +1800,6 @@ function commitDeletion(
1800 }
1801
1802 function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1833 - if (!supportsMutation) {
1834 - switch (finishedWork.tag) {
1835 - case FunctionComponent:
1836 - case ForwardRef:
1837 - case MemoComponent:
1838 - case SimpleMemoComponent: {
1839 - commitHookEffectListUnmount(
1840 - HookInsertion | HookHasEffect,
1841 - finishedWork,
1842 - finishedWork.return,
1843 - );
1844 - commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork);
1845 -
1846 - // Layout effects are destroyed during the mutation phase so that all
1847 - // destroy functions for all fibers are called before any create functions.
1848 - // This prevents sibling component effects from interfering with each other,
1849 - // e.g. a destroy function in one component should never override a ref set
1850 - // by a create function in another component during the same commit.
1851 - // TODO: Check if we're inside an Offscreen subtree that disappeared
1852 - // during this commit. If so, we would have already unmounted its
1853 - // layout hooks. (However, since we null out the `destroy` function
1854 - // right before calling it, the behavior is already correct, so this
1855 - // would mostly be for modeling purposes.)
1856 - if (
1857 - enableProfilerTimer &&
1858 - enableProfilerCommitHooks &&
1859 - finishedWork.mode & ProfileMode
1860 - ) {
1861 - try {
1862 - startLayoutEffectTimer();
1863 - commitHookEffectListUnmount(
1864 - HookLayout | HookHasEffect,
1865 - finishedWork,
1866 - finishedWork.return,
1867 - );
1868 - } finally {
1869 - recordLayoutEffectDuration(finishedWork);
1870 - }
1871 - } else {
1872 - commitHookEffectListUnmount(
1873 - HookLayout | HookHasEffect,
1874 - finishedWork,
1875 - finishedWork.return,
1876 - );
1877 - }
1878 - return;
1879 - }
1880 - case Profiler: {
1881 - return;
1882 - }
1883 - case SuspenseComponent: {
1884 - commitSuspenseCallback(finishedWork);
1885 - attachSuspenseRetryListeners(finishedWork);
1886 - return;
1887 - }
1888 - case SuspenseListComponent: {
1889 - attachSuspenseRetryListeners(finishedWork);
1890 - return;
1891 - }
1892 - case HostRoot: {
1893 - if (supportsHydration) {
1894 - if (current !== null) {
1895 - const prevRootState: RootState = current.memoizedState;
1896 - if (prevRootState.isDehydrated) {
1897 - const root: FiberRoot = finishedWork.stateNode;
1898 - commitHydratedContainer(root.containerInfo);
1899 - }
1900 - }
1901 - }
1902 - break;
1903 - }
1904 - case OffscreenComponent:
1905 - case LegacyHiddenComponent: {
1906 - return;
1907 - }
1908 - }
1909 -
1910 - commitContainer(finishedWork);
1911 - return;
1912 - }
1913 -
1803 switch (finishedWork.tag) {
1804 case FunctionComponent:
1805 case ForwardRef:
@@ -1955,51 +1844,55 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1844 return;
1845 }
1846 case HostComponent: {
1958 - const instance: Instance = finishedWork.stateNode;
1959 - if (instance != null) {
1960 - // Commit the work prepared earlier.
1961 - const newProps = finishedWork.memoizedProps;
1962 - // For hydration we reuse the update path but we treat the oldProps
1963 - // as the newProps. The updatePayload will contain the real change in
1964 - // this case.
1965 - const oldProps = current !== null ? current.memoizedProps : newProps;
1966 - const type = finishedWork.type;
1967 - // TODO: Type the updateQueue to be specific to host components.
1968 - const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);
1969 - finishedWork.updateQueue = null;
1970 - if (updatePayload !== null) {
1971 - commitUpdate(
1972 - instance,
1973 - updatePayload,
1974 - type,
1975 - oldProps,
1976 - newProps,
1977 - finishedWork,
1978 - );
1847 + if (supportsMutation) {
1848 + const instance: Instance = finishedWork.stateNode;
1849 + if (instance != null) {
1850 + // Commit the work prepared earlier.
1851 + const newProps = finishedWork.memoizedProps;
1852 + // For hydration we reuse the update path but we treat the oldProps
1853 + // as the newProps. The updatePayload will contain the real change in
1854 + // this case.
1855 + const oldProps = current !== null ? current.memoizedProps : newProps;
1856 + const type = finishedWork.type;
1857 + // TODO: Type the updateQueue to be specific to host components.
1858 + const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);
1859 + finishedWork.updateQueue = null;
1860 + if (updatePayload !== null) {
1861 + commitUpdate(
1862 + instance,
1863 + updatePayload,
1864 + type,
1865 + oldProps,
1866 + newProps,
1867 + finishedWork,
1868 + );
1869 + }
1870 }
1871 }
1872 return;
1873 }
1874 case HostText: {
1984 - if (finishedWork.stateNode === null) {
1985 - throw new Error(
1986 - 'This should have a text node initialized. This error is likely ' +
1987 - 'caused by a bug in React. Please file an issue.',
1988 - );
1989 - }
1875 + if (supportsMutation) {
1876 + if (finishedWork.stateNode === null) {
1877 + throw new Error(
1878 + 'This should have a text node initialized. This error is likely ' +
1879 + 'caused by a bug in React. Please file an issue.',
1880 + );
1881 + }
1882
1991 - const textInstance: TextInstance = finishedWork.stateNode;
1992 - const newText: string = finishedWork.memoizedProps;
1993 - // For hydration we reuse the update path but we treat the oldProps
1994 - // as the newProps. The updatePayload will contain the real change in
1995 - // this case.
1996 - const oldText: string =
1997 - current !== null ? current.memoizedProps : newText;
1998 - commitTextUpdate(textInstance, oldText, newText);
1883 + const textInstance: TextInstance = finishedWork.stateNode;
1884 + const newText: string = finishedWork.memoizedProps;
1885 + // For hydration we reuse the update path but we treat the oldProps
1886 + // as the newProps. The updatePayload will contain the real change in
1887 + // this case.
1888 + const oldText: string =
1889 + current !== null ? current.memoizedProps : newText;
1890 + commitTextUpdate(textInstance, oldText, newText);
1891 + }
1892 return;
1893 }
1894 case HostRoot: {
2002 - if (supportsHydration) {
1895 + if (supportsMutation && supportsHydration) {
1896 if (current !== null) {
1897 const prevRootState: RootState = current.memoizedState;
1898 if (prevRootState.isDehydrated) {
@@ -2008,6 +1901,21 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1901 }
1902 }
1903 }
1904 + if (supportsPersistence) {
1905 + const fiberRoot: FiberRoot = finishedWork.stateNode;
1906 + const containerInfo = fiberRoot.containerInfo;
1907 + const pendingChildren = fiberRoot.pendingChildren;
1908 + replaceContainerChildren(containerInfo, pendingChildren);
1909 + }
1910 + return;
1911 + }
1912 + case HostPortal: {
1913 + if (supportsPersistence) {
1914 + const portal = finishedWork.stateNode;
1915 + const containerInfo = portal.containerInfo;
1916 + const pendingChildren = portal.pendingChildren;
1917 + replaceContainerChildren(containerInfo, pendingChildren);
1918 + }
1919 return;
1920 }
1921 case Profiler: {
packages/react-reconciler/src/ReactFiberCommitWork.old.js
+55 -147
@@ -1481,36 +1481,6 @@ function emptyPortalContainer(current: Fiber) {
1481 replaceContainerChildren(containerInfo, emptyChildSet);
1482 }
1483
1484 -function commitContainer(finishedWork: Fiber) {
1485 - if (!supportsPersistence) {
1486 - return;
1487 - }
1488 -
1489 - switch (finishedWork.tag) {
1490 - case ClassComponent:
1491 - case HostComponent:
1492 - case HostText: {
1493 - return;
1494 - }
1495 - case HostRoot:
1496 - case HostPortal: {
1497 - const portalOrRoot: {
1498 - containerInfo: Container,
1499 - pendingChildren: ChildSet,
1500 - ...
1501 - } = finishedWork.stateNode;
1502 - const {containerInfo, pendingChildren} = portalOrRoot;
1503 - replaceContainerChildren(containerInfo, pendingChildren);
1504 - return;
1505 - }
1506 - }
1507 -
1508 - throw new Error(
1509 - 'This unit of work tag should not have side-effects. This error is ' +
1510 - 'likely caused by a bug in React. Please file an issue.',
1511 - );
1512 -}
1513 -
1484 function getHostParentFiber(fiber: Fiber): Fiber {
1485 let parent = fiber.return;
1486 while (parent !== null) {
@@ -1830,87 +1800,6 @@ function commitDeletion(
1800 }
1801
1802 function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1833 - if (!supportsMutation) {
1834 - switch (finishedWork.tag) {
1835 - case FunctionComponent:
1836 - case ForwardRef:
1837 - case MemoComponent:
1838 - case SimpleMemoComponent: {
1839 - commitHookEffectListUnmount(
1840 - HookInsertion | HookHasEffect,
1841 - finishedWork,
1842 - finishedWork.return,
1843 - );
1844 - commitHookEffectListMount(HookInsertion | HookHasEffect, finishedWork);
1845 -
1846 - // Layout effects are destroyed during the mutation phase so that all
1847 - // destroy functions for all fibers are called before any create functions.
1848 - // This prevents sibling component effects from interfering with each other,
1849 - // e.g. a destroy function in one component should never override a ref set
1850 - // by a create function in another component during the same commit.
1851 - // TODO: Check if we're inside an Offscreen subtree that disappeared
1852 - // during this commit. If so, we would have already unmounted its
1853 - // layout hooks. (However, since we null out the `destroy` function
1854 - // right before calling it, the behavior is already correct, so this
1855 - // would mostly be for modeling purposes.)
1856 - if (
1857 - enableProfilerTimer &&
1858 - enableProfilerCommitHooks &&
1859 - finishedWork.mode & ProfileMode
1860 - ) {
1861 - try {
1862 - startLayoutEffectTimer();
1863 - commitHookEffectListUnmount(
1864 - HookLayout | HookHasEffect,
1865 - finishedWork,
1866 - finishedWork.return,
1867 - );
1868 - } finally {
1869 - recordLayoutEffectDuration(finishedWork);
1870 - }
1871 - } else {
1872 - commitHookEffectListUnmount(
1873 - HookLayout | HookHasEffect,
1874 - finishedWork,
1875 - finishedWork.return,
1876 - );
1877 - }
1878 - return;
1879 - }
1880 - case Profiler: {
1881 - return;
1882 - }
1883 - case SuspenseComponent: {
1884 - commitSuspenseCallback(finishedWork);
1885 - attachSuspenseRetryListeners(finishedWork);
1886 - return;
1887 - }
1888 - case SuspenseListComponent: {
1889 - attachSuspenseRetryListeners(finishedWork);
1890 - return;
1891 - }
1892 - case HostRoot: {
1893 - if (supportsHydration) {
1894 - if (current !== null) {
1895 - const prevRootState: RootState = current.memoizedState;
1896 - if (prevRootState.isDehydrated) {
1897 - const root: FiberRoot = finishedWork.stateNode;
1898 - commitHydratedContainer(root.containerInfo);
1899 - }
1900 - }
1901 - }
1902 - break;
1903 - }
1904 - case OffscreenComponent:
1905 - case LegacyHiddenComponent: {
1906 - return;
1907 - }
1908 - }
1909 -
1910 - commitContainer(finishedWork);
1911 - return;
1912 - }
1913 -
1803 switch (finishedWork.tag) {
1804 case FunctionComponent:
1805 case ForwardRef:
@@ -1955,51 +1844,55 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1844 return;
1845 }
1846 case HostComponent: {
1958 - const instance: Instance = finishedWork.stateNode;
1959 - if (instance != null) {
1960 - // Commit the work prepared earlier.
1961 - const newProps = finishedWork.memoizedProps;
1962 - // For hydration we reuse the update path but we treat the oldProps
1963 - // as the newProps. The updatePayload will contain the real change in
1964 - // this case.
1965 - const oldProps = current !== null ? current.memoizedProps : newProps;
1966 - const type = finishedWork.type;
1967 - // TODO: Type the updateQueue to be specific to host components.
1968 - const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);
1969 - finishedWork.updateQueue = null;
1970 - if (updatePayload !== null) {
1971 - commitUpdate(
1972 - instance,
1973 - updatePayload,
1974 - type,
1975 - oldProps,
1976 - newProps,
1977 - finishedWork,
1978 - );
1847 + if (supportsMutation) {
1848 + const instance: Instance = finishedWork.stateNode;
1849 + if (instance != null) {
1850 + // Commit the work prepared earlier.
1851 + const newProps = finishedWork.memoizedProps;
1852 + // For hydration we reuse the update path but we treat the oldProps
1853 + // as the newProps. The updatePayload will contain the real change in
1854 + // this case.
1855 + const oldProps = current !== null ? current.memoizedProps : newProps;
1856 + const type = finishedWork.type;
1857 + // TODO: Type the updateQueue to be specific to host components.
1858 + const updatePayload: null | UpdatePayload = (finishedWork.updateQueue: any);
1859 + finishedWork.updateQueue = null;
1860 + if (updatePayload !== null) {
1861 + commitUpdate(
1862 + instance,
1863 + updatePayload,
1864 + type,
1865 + oldProps,
1866 + newProps,
1867 + finishedWork,
1868 + );
1869 + }
1870 }
1871 }
1872 return;
1873 }
1874 case HostText: {
1984 - if (finishedWork.stateNode === null) {
1985 - throw new Error(
1986 - 'This should have a text node initialized. This error is likely ' +
1987 - 'caused by a bug in React. Please file an issue.',
1988 - );
1989 - }
1875 + if (supportsMutation) {
1876 + if (finishedWork.stateNode === null) {
1877 + throw new Error(
1878 + 'This should have a text node initialized. This error is likely ' +
1879 + 'caused by a bug in React. Please file an issue.',
1880 + );
1881 + }
1882
1991 - const textInstance: TextInstance = finishedWork.stateNode;
1992 - const newText: string = finishedWork.memoizedProps;
1993 - // For hydration we reuse the update path but we treat the oldProps
1994 - // as the newProps. The updatePayload will contain the real change in
1995 - // this case.
1996 - const oldText: string =
1997 - current !== null ? current.memoizedProps : newText;
1998 - commitTextUpdate(textInstance, oldText, newText);
1883 + const textInstance: TextInstance = finishedWork.stateNode;
1884 + const newText: string = finishedWork.memoizedProps;
1885 + // For hydration we reuse the update path but we treat the oldProps
1886 + // as the newProps. The updatePayload will contain the real change in
1887 + // this case.
1888 + const oldText: string =
1889 + current !== null ? current.memoizedProps : newText;
1890 + commitTextUpdate(textInstance, oldText, newText);
1891 + }
1892 return;
1893 }
1894 case HostRoot: {
2002 - if (supportsHydration) {
1895 + if (supportsMutation && supportsHydration) {
1896 if (current !== null) {
1897 const prevRootState: RootState = current.memoizedState;
1898 if (prevRootState.isDehydrated) {
@@ -2008,6 +1901,21 @@ function commitWork(current: Fiber | null, finishedWork: Fiber): void {
1901 }
1902 }
1903 }
1904 + if (supportsPersistence) {
1905 + const fiberRoot: FiberRoot = finishedWork.stateNode;
1906 + const containerInfo = fiberRoot.containerInfo;
1907 + const pendingChildren = fiberRoot.pendingChildren;
1908 + replaceContainerChildren(containerInfo, pendingChildren);
1909 + }
1910 + return;
1911 + }
1912 + case HostPortal: {
1913 + if (supportsPersistence) {
1914 + const portal = finishedWork.stateNode;
1915 + const containerInfo = portal.containerInfo;
1916 + const pendingChildren = portal.pendingChildren;
1917 + replaceContainerChildren(containerInfo, pendingChildren);
1918 + }
1919 return;
1920 }
1921 case Profiler: {