The Lost Effect, chapter 3
wow, writing code is hard
Sophie Alpert committed
Oct 12, 2018 at 18:04 UTC
75a1c2e72a8ebff2ec5e9b89e3c0e04f576731b7
6 files changed
+43
-39
packages/react-reconciler/src/ReactFiberClassComponent.js
+4
-4
@@ -51,7 +51,7 @@ import {
51
requestCurrentTime,
52
computeExpirationForFiber,
53
scheduleWork,
54
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber,
54
+ flushPassiveEffects,
55
} from './ReactFiberScheduler';
56
57
const ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner;
@@ -200,7 +200,7 @@ const classComponentUpdater = {
200
update.callback = callback;
201
}
202
203
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber(fiber);
203
+ flushPassiveEffects();
204
enqueueUpdate(fiber, update);
205
scheduleWork(fiber, expirationTime);
206
},
@@ -220,7 +220,7 @@ const classComponentUpdater = {
220
update.callback = callback;
221
}
222
223
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber(fiber);
223
+ flushPassiveEffects();
224
enqueueUpdate(fiber, update);
225
scheduleWork(fiber, expirationTime);
226
},
@@ -239,7 +239,7 @@ const classComponentUpdater = {
239
update.callback = callback;
240
}
241
242
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber(fiber);
242
+ flushPassiveEffects();
243
enqueueUpdate(fiber, update);
244
scheduleWork(fiber, expirationTime);
245
},
packages/react-reconciler/src/ReactFiberCommitWork.js
+2
-2
@@ -85,7 +85,7 @@ import {
85
} from './ReactFiberHostConfig';
86
import {
87
captureCommitPhaseError,
88
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber,
88
+ flushPassiveEffects,
89
requestCurrentTime,
90
scheduleWork,
91
} from './ReactFiberScheduler';
@@ -457,7 +457,7 @@ function commitLifeCycles(
457
timedOutAt: NoWork,
458
};
459
finishedWork.memoizedState = newState;
460
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber(finishedWork);
460
+ flushPassiveEffects();
461
scheduleWork(finishedWork, Sync);
462
return;
463
}
packages/react-reconciler/src/ReactFiberHooks.js
+2
-2
@@ -32,7 +32,7 @@ import {
32
import {
33
scheduleWork,
34
computeExpirationForFiber,
35
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber,
35
+ flushPassiveEffects,
36
requestCurrentTime,
37
} from './ReactFiberScheduler';
38
@@ -725,7 +725,7 @@ function dispatchAction<S, A>(
725
callback: callback !== undefined ? callback : null,
726
next: null,
727
};
728
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber(fiber);
728
+ flushPassiveEffects();
729
// Append the update to the end of the list.
730
const last = queue.last;
731
if (last === null) {
packages/react-reconciler/src/ReactFiberReconciler.js
+2
-2
@@ -52,7 +52,7 @@ import {
52
syncUpdates,
53
interactiveUpdates,
54
flushInteractiveUpdates,
55
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber,
55
+ flushPassiveEffects,
56
} from './ReactFiberScheduler';
57
import {createUpdate, enqueueUpdate} from './ReactUpdateQueue';
58
import ReactFiberInstrumentation from './ReactFiberInstrumentation';
@@ -147,7 +147,7 @@ function scheduleRootUpdate(
147
update.callback = callback;
148
}
149
150
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber(current);
150
+ flushPassiveEffects();
151
enqueueUpdate(current, update);
152
scheduleWork(current, expirationTime);
153
packages/react-reconciler/src/ReactFiberScheduler.js
+4
-29
@@ -578,33 +578,8 @@ function markLegacyErrorBoundaryAsFailed(instance: mixed) {
578
}
579
}
580
581
-function flushPassiveEffectsBeforeSchedulingUpdateOnFiber(fiber: Fiber) {
582
- if (rootWithPendingPassiveEffects !== null) {
583
- // TODO: This is an unfortunate extra loop. We end up traversing to the root
584
- // again in scheduleWorkToRoot. But we have to do this one first because it
585
- // needs to happen before adding an update to the queue, and
586
- // scheduleWorkToRoot may perform a synchronous re-render. Maybe we can
587
- // solve this with batchedUpdates, or with the equivalent in the Scheduler
588
- // package.
589
- let node = fiber;
590
- do {
591
- switch (node.tag) {
592
- case HostRoot: {
593
- const root: FiberRoot = node.stateNode;
594
- flushPassiveEffects(root);
595
- return;
596
- }
597
- }
598
- node = node.return;
599
- } while (node !== null);
600
- }
601
-}
602
-
603
-function flushPassiveEffects(root: FiberRoot) {
604
- if (
605
- passiveEffectCallback !== null &&
606
- root === rootWithPendingPassiveEffects
607
- ) {
581
+function flushPassiveEffects() {
582
+ if (passiveEffectCallback !== null) {
583
Schedule_cancelCallback(passiveEffectCallbackHandle);
584
// We call the scheduled callback instead of commitPassiveEffects directly
585
// to ensure tracing works correctly.
@@ -1248,7 +1223,7 @@ function renderRoot(
1223
'by a bug in React. Please file an issue.',
1224
);
1225
1251
- flushPassiveEffects(root);
1226
+ flushPassiveEffects();
1227
1228
isWorking = true;
1229
ReactCurrentOwner.currentDispatcher = Dispatcher;
@@ -2613,5 +2588,5 @@ export {
2588
interactiveUpdates,
2589
flushInteractiveUpdates,
2590
computeUniqueAsyncExpiration,
2616
- flushPassiveEffectsBeforeSchedulingUpdateOnFiber,
2591
+ flushPassiveEffects,
2592
};
packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js
+29
@@ -717,6 +717,35 @@ describe('ReactHooks', () => {
717
]);
718
});
719
720
+ it('flushes passive effects even if siblings schedule a new root', () => {
721
+ function PassiveEffect(props) {
722
+ useEffect(() => {
723
+ ReactNoop.yield('Passive effect');
724
+ }, []);
725
+ return <Text text="Passive" />;
726
+ }
727
+ function LayoutEffect(props) {
728
+ useLayoutEffect(() => {
729
+ ReactNoop.yield('Layout effect');
730
+ // Scheduling work shouldn't interfere with the queued passive effect
731
+ ReactNoop.renderToRootWithID(<Text text="New Root" />, 'root2');
732
+ });
733
+ return <Text text="Layout" />;
734
+ }
735
+ ReactNoop.render([<PassiveEffect key="p" />, <LayoutEffect key="l" />]);
736
+ expect(ReactNoop.flush()).toEqual([
737
+ 'Passive',
738
+ 'Layout',
739
+ 'Layout effect',
740
+ 'Passive effect',
741
+ 'New Root',
742
+ ]);
743
+ expect(ReactNoop.getChildren()).toEqual([
744
+ span('Passive'),
745
+ span('Layout'),
746
+ ]);
747
+ });
748
+
749
it(
750
'flushes effects serially by flushing old effects before flushing ' +
751
"new ones, if they haven't already fired",