Skip to content

Commit 763d5f2

Browse files
committed
Land effects refactor in main fork
yarn replace-fork yarn lint --fix I also updated the eslint config to remove `subtreeTags` from list of disallowed fields in the old fork.
1 parent ad8d4bc commit 763d5f2

14 files changed

+2689
-1403
lines changed

.eslintrc.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,7 @@ module.exports = {
113113
'react-internal/warning-args': ERROR,
114114
'react-internal/no-production-logging': ERROR,
115115
'react-internal/no-cross-fork-imports': ERROR,
116-
'react-internal/no-cross-fork-types': [
117-
ERROR,
118-
{
119-
old: [
120-
'firstEffect',
121-
'nextEffect',
122-
// Disabled because it's also used by the Hook type.
123-
// 'lastEffect',
124-
],
125-
new: ['subtreeFlags'],
126-
},
127-
],
116+
'react-internal/no-cross-fork-types': ERROR,
128117
},
129118

130119
overrides: [

packages/react-reconciler/src/ReactChildFiber.old.js

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type {Fiber} from './ReactInternalTypes';
1515
import type {Lanes} from './ReactFiberLane';
1616

1717
import getComponentName from 'shared/getComponentName';
18-
import {Placement, Deletion} from './ReactFiberFlags';
18+
import {Deletion, Placement} from './ReactFiberFlags';
1919
import {
2020
getIteratorFn,
2121
REACT_ELEMENT_TYPE,
@@ -277,20 +277,13 @@ function ChildReconciler(shouldTrackSideEffects) {
277277
// Noop.
278278
return;
279279
}
280-
// Deletions are added in reversed order so we add it to the front.
281-
// At this point, the return fiber's effect list is empty except for
282-
// deletions, so we can just append the deletion to the list. The remaining
283-
// effects aren't added until the complete phase. Once we implement
284-
// resuming, this may not be true.
285-
const last = returnFiber.lastEffect;
286-
if (last !== null) {
287-
last.nextEffect = childToDelete;
288-
returnFiber.lastEffect = childToDelete;
280+
const deletions = returnFiber.deletions;
281+
if (deletions === null) {
282+
returnFiber.deletions = [childToDelete];
283+
returnFiber.flags |= Deletion;
289284
} else {
290-
returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
285+
deletions.push(childToDelete);
291286
}
292-
childToDelete.nextEffect = null;
293-
childToDelete.flags = Deletion;
294287
}
295288

296289
function deleteRemainingChildren(

packages/react-reconciler/src/ReactFiber.old.js

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
enableScopeAPI,
3030
enableBlocksAPI,
3131
} from 'shared/ReactFeatureFlags';
32-
import {NoFlags, Placement} from './ReactFiberFlags';
32+
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
3333
import {ConcurrentRoot, BlockingRoot} from './ReactRootTags';
3434
import {
3535
IndeterminateComponent,
@@ -144,10 +144,8 @@ function FiberNode(
144144

145145
// Effects
146146
this.flags = NoFlags;
147-
this.nextEffect = null;
148-
149-
this.firstEffect = null;
150-
this.lastEffect = null;
147+
this.subtreeFlags = NoFlags;
148+
this.deletions = null;
151149

152150
this.lanes = NoLanes;
153151
this.childLanes = NoLanes;
@@ -285,13 +283,8 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
285283
workInProgress.type = current.type;
286284

287285
// We already have an alternate.
288-
// Reset the effect tag.
289-
workInProgress.flags = NoFlags;
290-
291-
// The effect list is no longer valid.
292-
workInProgress.nextEffect = null;
293-
workInProgress.firstEffect = null;
294-
workInProgress.lastEffect = null;
286+
workInProgress.subtreeFlags = NoFlags;
287+
workInProgress.deletions = null;
295288

296289
if (enableProfilerTimer) {
297290
// We intentionally reset, rather than copy, actualDuration & actualStartTime.
@@ -303,6 +296,9 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
303296
}
304297
}
305298

299+
// Reset all effects except static ones.
300+
// Static effects are not specific to a render.
301+
workInProgress.flags = current.flags & StaticMask;
306302
workInProgress.childLanes = current.childLanes;
307303
workInProgress.lanes = current.lanes;
308304

@@ -368,18 +364,14 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
368364
// that child fiber is setting, not the reconciliation.
369365
workInProgress.flags &= Placement;
370366

371-
// The effect list is no longer valid.
372-
workInProgress.nextEffect = null;
373-
workInProgress.firstEffect = null;
374-
workInProgress.lastEffect = null;
375-
376367
const current = workInProgress.alternate;
377368
if (current === null) {
378369
// Reset to createFiber's initial values.
379370
workInProgress.childLanes = NoLanes;
380371
workInProgress.lanes = renderLanes;
381372

382373
workInProgress.child = null;
374+
workInProgress.subtreeFlags = NoFlags;
383375
workInProgress.memoizedProps = null;
384376
workInProgress.memoizedState = null;
385377
workInProgress.updateQueue = null;
@@ -400,6 +392,8 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
400392
workInProgress.lanes = current.lanes;
401393

402394
workInProgress.child = current.child;
395+
workInProgress.subtreeFlags = current.subtreeFlags;
396+
workInProgress.deletions = null;
403397
workInProgress.memoizedProps = current.memoizedProps;
404398
workInProgress.memoizedState = current.memoizedState;
405399
workInProgress.updateQueue = current.updateQueue;
@@ -822,9 +816,8 @@ export function assignFiberPropertiesInDEV(
822816
target.dependencies = source.dependencies;
823817
target.mode = source.mode;
824818
target.flags = source.flags;
825-
target.nextEffect = source.nextEffect;
826-
target.firstEffect = source.firstEffect;
827-
target.lastEffect = source.lastEffect;
819+
target.subtreeFlags = source.subtreeFlags;
820+
target.deletions = source.deletions;
828821
target.lanes = source.lanes;
829822
target.childLanes = source.childLanes;
830823
target.alternate = source.alternate;

packages/react-reconciler/src/ReactFiberBeginWork.old.js

Lines changed: 26 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ import {
6060
Hydrating,
6161
ContentReset,
6262
DidCapture,
63-
Update,
6463
Ref,
6564
Deletion,
6665
ForceUpdateForLegacySuspense,
66+
StaticMask,
6767
} from './ReactFiberFlags';
6868
import ReactSharedInternals from 'shared/ReactSharedInternals';
6969
import {
@@ -674,8 +674,6 @@ function updateProfiler(
674674
renderLanes: Lanes,
675675
) {
676676
if (enableProfilerTimer) {
677-
workInProgress.flags |= Update;
678-
679677
// Reset effect durations for the next eventual effect phase.
680678
// These are reset during render to allow the DevTools commit hook a chance to read them,
681679
const stateNode = workInProgress.stateNode;
@@ -1151,6 +1149,9 @@ function updateHostComponent(
11511149
workInProgress.flags |= ContentReset;
11521150
}
11531151

1152+
// React DevTools reads this flag.
1153+
workInProgress.flags |= PerformedWork;
1154+
11541155
markRef(current, workInProgress);
11551156
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
11561157
return workInProgress.child;
@@ -2090,9 +2091,14 @@ function updateSuspensePrimaryChildren(
20902091
primaryChildFragment.sibling = null;
20912092
if (currentFallbackChildFragment !== null) {
20922093
// Delete the fallback child fragment
2093-
currentFallbackChildFragment.nextEffect = null;
2094-
currentFallbackChildFragment.flags = Deletion;
2095-
workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChildFragment;
2094+
const deletions = workInProgress.deletions;
2095+
if (deletions === null) {
2096+
workInProgress.deletions = [currentFallbackChildFragment];
2097+
// TODO (effects) Rename this to better reflect its new usage (e.g. ChildDeletions)
2098+
workInProgress.flags |= Deletion;
2099+
} else {
2100+
deletions.push(currentFallbackChildFragment);
2101+
}
20962102
}
20972103

20982104
workInProgress.child = primaryChildFragment;
@@ -2149,24 +2155,19 @@ function updateSuspenseFallbackChildren(
21492155

21502156
// The fallback fiber was added as a deletion effect during the first pass.
21512157
// However, since we're going to remain on the fallback, we no longer want
2152-
// to delete it. So we need to remove it from the list. Deletions are stored
2153-
// on the same list as effects. We want to keep the effects from the primary
2154-
// tree. So we copy the primary child fragment's effect list, which does not
2155-
// include the fallback deletion effect.
2156-
const progressedLastEffect = primaryChildFragment.lastEffect;
2157-
if (progressedLastEffect !== null) {
2158-
workInProgress.firstEffect = primaryChildFragment.firstEffect;
2159-
workInProgress.lastEffect = progressedLastEffect;
2160-
progressedLastEffect.nextEffect = null;
2161-
} else {
2162-
// TODO: Reset this somewhere else? Lol legacy mode is so weird.
2163-
workInProgress.firstEffect = workInProgress.lastEffect = null;
2164-
}
2158+
// to delete it.
2159+
workInProgress.deletions = null;
21652160
} else {
21662161
primaryChildFragment = createWorkInProgressOffscreenFiber(
21672162
currentPrimaryChildFragment,
21682163
primaryChildProps,
21692164
);
2165+
2166+
// Since we're reusing a current tree, we need to reuse the flags, too.
2167+
// (We don't do this in legacy mode, because in legacy mode we don't re-use
2168+
// the current tree; see previous branch.)
2169+
primaryChildFragment.subtreeFlags =
2170+
currentPrimaryChildFragment.subtreeFlags & StaticMask;
21702171
}
21712172
let fallbackChildFragment;
21722173
if (currentFallbackChildFragment !== null) {
@@ -2651,7 +2652,6 @@ function initSuspenseListRenderState(
26512652
tail: null | Fiber,
26522653
lastContentRow: null | Fiber,
26532654
tailMode: SuspenseListTailMode,
2654-
lastEffectBeforeRendering: null | Fiber,
26552655
): void {
26562656
const renderState: null | SuspenseListRenderState =
26572657
workInProgress.memoizedState;
@@ -2663,7 +2663,6 @@ function initSuspenseListRenderState(
26632663
last: lastContentRow,
26642664
tail: tail,
26652665
tailMode: tailMode,
2666-
lastEffect: lastEffectBeforeRendering,
26672666
}: SuspenseListRenderState);
26682667
} else {
26692668
// We can reuse the existing object from previous renders.
@@ -2673,7 +2672,6 @@ function initSuspenseListRenderState(
26732672
renderState.last = lastContentRow;
26742673
renderState.tail = tail;
26752674
renderState.tailMode = tailMode;
2676-
renderState.lastEffect = lastEffectBeforeRendering;
26772675
}
26782676
}
26792677

@@ -2755,7 +2753,6 @@ function updateSuspenseListComponent(
27552753
tail,
27562754
lastContentRow,
27572755
tailMode,
2758-
workInProgress.lastEffect,
27592756
);
27602757
break;
27612758
}
@@ -2787,7 +2784,6 @@ function updateSuspenseListComponent(
27872784
tail,
27882785
null, // last
27892786
tailMode,
2790-
workInProgress.lastEffect,
27912787
);
27922788
break;
27932789
}
@@ -2798,7 +2794,6 @@ function updateSuspenseListComponent(
27982794
null, // tail
27992795
null, // last
28002796
undefined,
2801-
workInProgress.lastEffect,
28022797
);
28032798
break;
28042799
}
@@ -3058,15 +3053,14 @@ function remountFiber(
30583053

30593054
// Delete the old fiber and place the new one.
30603055
// Since the old fiber is disconnected, we have to schedule it manually.
3061-
const last = returnFiber.lastEffect;
3062-
if (last !== null) {
3063-
last.nextEffect = current;
3064-
returnFiber.lastEffect = current;
3056+
const deletions = returnFiber.deletions;
3057+
if (deletions === null) {
3058+
returnFiber.deletions = [current];
3059+
// TODO (effects) Rename this to better reflect its new usage (e.g. ChildDeletions)
3060+
returnFiber.flags |= Deletion;
30653061
} else {
3066-
returnFiber.firstEffect = returnFiber.lastEffect = current;
3062+
deletions.push(current);
30673063
}
3068-
current.nextEffect = null;
3069-
current.flags = Deletion;
30703064

30713065
newWorkInProgress.flags |= Placement;
30723066

@@ -3151,15 +3145,6 @@ function beginWork(
31513145
}
31523146
case Profiler:
31533147
if (enableProfilerTimer) {
3154-
// Profiler should only call onRender when one of its descendants actually rendered.
3155-
const hasChildWork = includesSomeLane(
3156-
renderLanes,
3157-
workInProgress.childLanes,
3158-
);
3159-
if (hasChildWork) {
3160-
workInProgress.flags |= Update;
3161-
}
3162-
31633148
// Reset effect durations for the next eventual effect phase.
31643149
// These are reset during render to allow the DevTools commit hook a chance to read them,
31653150
const stateNode = workInProgress.stateNode;
@@ -3266,7 +3251,6 @@ function beginWork(
32663251
// update in the past but didn't complete it.
32673252
renderState.rendering = null;
32683253
renderState.tail = null;
3269-
renderState.lastEffect = null;
32703254
}
32713255
pushSuspenseContext(workInProgress, suspenseStackCursor.current);
32723256

0 commit comments

Comments
 (0)