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