Skip to content

Commit af709c9

Browse files
committed
Feature flag to revert facebook#15650
PR facebook#15650 is a bugfix but it's technically a semantic change that could cause regressions. I don't think it will be an issue, since the previous behavior was both broken and incoherent, but out of an abundance of caution, let's wrap it in a flag so we can easily revert it if necessary.
1 parent 668fbd6 commit af709c9

12 files changed

+94
-6
lines changed

Diff for: packages/react-reconciler/src/ReactFiberClassComponent.js

+10
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
requestCurrentTime,
5353
computeExpirationForFiber,
5454
scheduleWork,
55+
flushPassiveEffects,
5556
} from './ReactFiberScheduler';
5657

5758
const fakeInternalInstance = {};
@@ -193,6 +194,9 @@ const classComponentUpdater = {
193194
update.callback = callback;
194195
}
195196

197+
if (revertPassiveEffectsChange) {
198+
flushPassiveEffects();
199+
}
196200
enqueueUpdate(fiber, update);
197201
scheduleWork(fiber, expirationTime);
198202
},
@@ -212,6 +216,9 @@ const classComponentUpdater = {
212216
update.callback = callback;
213217
}
214218

219+
if (revertPassiveEffectsChange) {
220+
flushPassiveEffects();
221+
}
215222
enqueueUpdate(fiber, update);
216223
scheduleWork(fiber, expirationTime);
217224
},
@@ -230,6 +237,9 @@ const classComponentUpdater = {
230237
update.callback = callback;
231238
}
232239

240+
if (revertPassiveEffectsChange) {
241+
flushPassiveEffects();
242+
}
233243
enqueueUpdate(fiber, update);
234244
scheduleWork(fiber, expirationTime);
235245
},

Diff for: packages/react-reconciler/src/ReactFiberHooks.js

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
import {
3232
scheduleWork,
3333
computeExpirationForFiber,
34+
flushPassiveEffects,
3435
requestCurrentTime,
3536
warnIfNotCurrentlyActingUpdatesInDev,
3637
markRenderEventTime,
@@ -41,6 +42,7 @@ import warning from 'shared/warning';
4142
import getComponentName from 'shared/getComponentName';
4243
import is from 'shared/objectIs';
4344
import {markWorkInProgressReceivedUpdate} from './ReactFiberBeginWork';
45+
import {revertPassiveEffectsChange} from 'shared/ReactFeatureFlags';
4446

4547
const {ReactCurrentDispatcher} = ReactSharedInternals;
4648

@@ -1107,6 +1109,10 @@ function dispatchAction<S, A>(
11071109
lastRenderPhaseUpdate.next = update;
11081110
}
11091111
} else {
1112+
if (revertPassiveEffectsChange) {
1113+
flushPassiveEffects();
1114+
}
1115+
11101116
const currentTime = requestCurrentTime();
11111117
const expirationTime = computeExpirationForFiber(currentTime, fiber);
11121118

Diff for: packages/react-reconciler/src/ReactFiberReconciler.js

+14
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ import {
6464
} from './ReactCurrentFiber';
6565
import {StrictMode} from './ReactTypeOfMode';
6666
import {Sync} from './ReactFiberExpirationTime';
67+
import {revertPassiveEffectsChange} from 'shared/ReactFeatureFlags';
6768

6869
type OpaqueRoot = FiberRoot;
6970

@@ -152,6 +153,9 @@ function scheduleRootUpdate(
152153
update.callback = callback;
153154
}
154155

156+
if (revertPassiveEffectsChange) {
157+
flushPassiveEffects();
158+
}
155159
enqueueUpdate(current, update);
156160
scheduleWork(current, expirationTime);
157161

@@ -391,6 +395,10 @@ if (__DEV__) {
391395
id--;
392396
}
393397
if (currentHook !== null) {
398+
if (revertPassiveEffectChange) {
399+
flushPassiveEffects();
400+
}
401+
394402
const newState = copyWithSet(currentHook.memoizedState, path, value);
395403
currentHook.memoizedState = newState;
396404
currentHook.baseState = newState;
@@ -408,6 +416,9 @@ if (__DEV__) {
408416

409417
// Support DevTools props for function components, forwardRef, memo, host components, etc.
410418
overrideProps = (fiber: Fiber, path: Array<string | number>, value: any) => {
419+
if (revertPassiveEffectChange) {
420+
flushPassiveEffects();
421+
}
411422
fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);
412423
if (fiber.alternate) {
413424
fiber.alternate.pendingProps = fiber.pendingProps;
@@ -416,6 +427,9 @@ if (__DEV__) {
416427
};
417428

418429
scheduleUpdate = (fiber: Fiber) => {
430+
if (revertPassiveEffectChange) {
431+
flushPassiveEffects();
432+
}
419433
scheduleWork(fiber, Sync);
420434
};
421435

Diff for: packages/react-reconciler/src/ReactFiberScheduler.js

+13-6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
enableProfilerTimer,
2525
disableYielding,
2626
enableSchedulerTracing,
27+
revertPassiveEffectsChange,
2728
} from 'shared/ReactFeatureFlags';
2829
import ReactSharedInternals from 'shared/ReactSharedInternals';
2930
import invariant from 'shared/invariant';
@@ -560,9 +561,11 @@ export function flushInteractiveUpdates() {
560561
return;
561562
}
562563
flushPendingDiscreteUpdates();
563-
// If the discrete updates scheduled passive effects, flush them now so that
564-
// they fire before the next serial event.
565-
flushPassiveEffects();
564+
if (!revertPassiveEffectsChange) {
565+
// If the discrete updates scheduled passive effects, flush them now so that
566+
// they fire before the next serial event.
567+
flushPassiveEffects();
568+
}
566569
}
567570

568571
function resolveLocksOnRoot(root: FiberRoot, expirationTime: ExpirationTime) {
@@ -598,8 +601,10 @@ export function interactiveUpdates<A, B, C, R>(
598601
// should explicitly call flushInteractiveUpdates.
599602
flushPendingDiscreteUpdates();
600603
}
601-
// TODO: Remove this call for the same reason as above.
602-
flushPassiveEffects();
604+
if (!revertPassiveEffectsChange) {
605+
// TODO: Remove this call for the same reason as above.
606+
flushPassiveEffects();
607+
}
603608
return runWithPriority(UserBlockingPriority, fn.bind(null, a, b, c));
604609
}
605610

@@ -750,7 +755,9 @@ function renderRoot(
750755
return commitRoot.bind(null, root);
751756
}
752757

753-
flushPassiveEffects();
758+
if (!revertPassiveEffectsChange) {
759+
flushPassiveEffects();
760+
}
754761

755762
// If the root or expiration time have changed, throw out the existing stack
756763
// and prepare a fresh one. Otherwise we'll continue where we left off.

Diff for: packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js

+42
Original file line numberDiff line numberDiff line change
@@ -2077,4 +2077,46 @@ describe('ReactHooksWithNoopRenderer', () => {
20772077
expect(Scheduler).toFlushAndYield(['Step: 5, Shadow: 5']);
20782078
expect(ReactNoop).toMatchRenderedOutput('5');
20792079
});
2080+
2081+
describe('revertPassiveEffectsChange', () => {
2082+
it('flushes serial effects before enqueueing work', () => {
2083+
jest.resetModules();
2084+
2085+
ReactFeatureFlags = require('shared/ReactFeatureFlags');
2086+
ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false;
2087+
ReactFeatureFlags.enableSchedulerTracing = true;
2088+
ReactFeatureFlags.revertPassiveEffectsChange = true;
2089+
React = require('react');
2090+
ReactNoop = require('react-noop-renderer');
2091+
Scheduler = require('scheduler');
2092+
SchedulerTracing = require('scheduler/tracing');
2093+
useState = React.useState;
2094+
useEffect = React.useEffect;
2095+
act = ReactNoop.act;
2096+
2097+
let _updateCount;
2098+
function Counter(props) {
2099+
const [count, updateCount] = useState(0);
2100+
_updateCount = updateCount;
2101+
useEffect(() => {
2102+
Scheduler.yieldValue(`Will set count to 1`);
2103+
updateCount(1);
2104+
}, []);
2105+
return <Text text={'Count: ' + count} />;
2106+
}
2107+
2108+
ReactNoop.render(<Counter count={0} />, () =>
2109+
Scheduler.yieldValue('Sync effect'),
2110+
);
2111+
expect(Scheduler).toFlushAndYieldThrough(['Count: 0', 'Sync effect']);
2112+
expect(ReactNoop.getChildren()).toEqual([span('Count: 0')]);
2113+
2114+
// Enqueuing this update forces the passive effect to be flushed --
2115+
// updateCount(1) happens first, so 2 wins.
2116+
act(() => _updateCount(2));
2117+
expect(Scheduler).toHaveYielded(['Will set count to 1']);
2118+
expect(Scheduler).toFlushAndYield(['Count: 2']);
2119+
expect(ReactNoop.getChildren()).toEqual([span('Count: 2')]);
2120+
});
2121+
});
20802122
});

Diff for: packages/shared/ReactFeatureFlags.js

+3
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,6 @@ export const enableEventAPI = false;
6767

6868
// New API for JSX transforms to target - https://github.com/reactjs/rfcs/pull/107
6969
export const enableJSXTransformAPI = false;
70+
71+
// Temporary flag to revert the fix in #15650
72+
export const revertPassiveEffectsChange = false;

Diff for: packages/shared/forks/ReactFeatureFlags.native-fb.js

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const warnAboutDeprecatedLifecycles = true;
3232
export const warnAboutDeprecatedSetNativeProps = true;
3333
export const enableEventAPI = false;
3434
export const enableJSXTransformAPI = false;
35+
export const revertPassiveEffectsChange = false;
3536

3637
// Only used in www builds.
3738
export function addUserTimingListener() {

Diff for: packages/shared/forks/ReactFeatureFlags.native-oss.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const enableSchedulerDebugging = false;
2929
export const warnAboutDeprecatedSetNativeProps = false;
3030
export const enableEventAPI = false;
3131
export const enableJSXTransformAPI = false;
32+
export const revertPassiveEffectsChange = false;
3233

3334
// Only used in www builds.
3435
export function addUserTimingListener() {

Diff for: packages/shared/forks/ReactFeatureFlags.persistent.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const enableSchedulerDebugging = false;
2929
export const warnAboutDeprecatedSetNativeProps = false;
3030
export const enableEventAPI = false;
3131
export const enableJSXTransformAPI = false;
32+
export const revertPassiveEffectsChange = false;
3233

3334
// Only used in www builds.
3435
export function addUserTimingListener() {

Diff for: packages/shared/forks/ReactFeatureFlags.test-renderer.js

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const enableSchedulerDebugging = false;
2929
export const warnAboutDeprecatedSetNativeProps = false;
3030
export const enableEventAPI = false;
3131
export const enableJSXTransformAPI = false;
32+
export const revertPassiveEffectsChange = false;
3233

3334
// Only used in www builds.
3435
export function addUserTimingListener() {

Diff for: packages/shared/forks/ReactFeatureFlags.test-renderer.www.js

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const disableJavaScriptURLs = false;
2727
export const disableYielding = false;
2828
export const enableEventAPI = true;
2929
export const enableJSXTransformAPI = true;
30+
export const revertPassiveEffectsChange = false;
3031

3132
// Only used in www builds.
3233
export function addUserTimingListener() {

Diff for: packages/shared/forks/ReactFeatureFlags.www.js

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export const {
2020
disableInputAttributeSyncing,
2121
warnAboutShorthandPropertyCollision,
2222
warnAboutDeprecatedSetNativeProps,
23+
revertPassiveEffectsChange,
2324
} = require('ReactFeatureFlags');
2425

2526
// In www, we have experimental support for gathering data

0 commit comments

Comments
 (0)