Compare commits

...

1 Commits

Author SHA1 Message Date
Rick Hanlon
ccdb07eea5 Failing unit test for infinite render issue 2023-04-29 13:24:07 -04:00
2 changed files with 98 additions and 20 deletions

View File

@@ -151,29 +151,17 @@ export function flushSyncWorkOnLegacyRootsOnly() {
flushSyncWorkAcrossRoots_impl(true);
}
function flushSyncWorkAcrossRoots_impl(onlyLegacy: boolean) {
if (isFlushingWork) {
// Prevent reentrancy.
// TODO: Is this overly defensive? The callers must check the execution
// context first regardless.
return;
}
if (!mightHavePendingSyncWork) {
// Fast path. There's no sync work to do.
return;
}
const workInProgressRoot = getWorkInProgressRoot();
const workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes();
// There may or may not be synchronous work scheduled. Let's check.
let didPerformSomeWork;
export function _doFlushWork(
firstRoot,
workInProgressRoot,
workInProgressRootRenderLanes,
onlyLegacy,
) {
let didPerformSomeWork = false;
let errors: Array<mixed> | null = null;
isFlushingWork = true;
do {
didPerformSomeWork = false;
let root = firstScheduledRoot;
let root = firstRoot;
while (root !== null) {
if (onlyLegacy && root.tag !== LegacyRoot) {
// Skip non-legacy roots.
@@ -202,6 +190,33 @@ function flushSyncWorkAcrossRoots_impl(onlyLegacy: boolean) {
root = root.next;
}
} while (didPerformSomeWork);
return errors;
}
function flushSyncWorkAcrossRoots_impl(onlyLegacy: boolean) {
if (isFlushingWork) {
// Prevent reentrancy.
// TODO: Is this overly defensive? The callers must check the execution
// context first regardless.
return;
}
if (!mightHavePendingSyncWork) {
// Fast path. There's no sync work to do.
return;
}
const workInProgressRoot = getWorkInProgressRoot();
const workInProgressRootRenderLanes = getWorkInProgressRootRenderLanes();
// There may or may not be synchronous work scheduled. Let's check.
isFlushingWork = true;
const errors = _doFlushWork(
firstScheduledRoot,
workInProgressRoot,
workInProgressRootRenderLanes,
onlyLegacy,
);
isFlushingWork = false;
// If any errors were thrown, rethrow them right before exiting.

View File

@@ -0,0 +1,63 @@
let _doFlushWork;
const shimHostConfigPath = 'react-reconciler/src/ReactFiberConfig';
jest.mock(shimHostConfigPath, () => {
return jest.requireActual(
'react-dom-bindings/src/client/ReactFiberConfigDOM.js',
);
});
beforeAll(() => {
_doFlushWork = require('../ReactFiberRootScheduler')._doFlushWork;
});
test('does not hang', () => {
const root = {
tag: 1,
pendingChildren: null,
pingCache: {},
finishedWork: null,
timeoutHandle: -1,
cancelPendingCommit: null,
context: {},
pendingContext: null,
next: null,
callbackNode: null,
callbackPriority: 0,
expirationTimes: [
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 278303.90000000596,
278417.1999999881, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1,
],
pendingLanes: 6176,
suspendedLanes: 0,
pingedLanes: 0,
expiredLanes: 0,
mutableReadLanes: 0,
finishedLanes: 0,
errorRecoveryDisabledLanes: 0,
entangledLanes: 6144,
entanglements: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6144, 6144, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
],
hiddenUpdates: [],
identifierPrefix: '',
pooledCache: null,
pooledCacheLanes: 0,
mutableSourceEagerHydrationData: null,
hydrationCallbacks: {
unstable_concurrentUpdatesByDefault: true,
unstable_strictMode: true,
},
incompleteTransitions: {},
effectDuration: 0,
passiveEffectDuration: 0,
memoizedUpdaters: {},
pendingUpdatersLaneMap: [],
_debugRootType: 'hydrateRoot()',
};
expect(() => {
_doFlushWork(root, root, 2, false);
}).not.toThrow();
});