Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -503,4 +503,23 @@ describe('ReactTestUtils.act()', () => {
});
}
});
describe('concurrent mode', () => {
it('flushes renders', () => {
function App() {
let [state, setState] = React.useState(0);
React.useEffect(
() => {
setState(x => x + 1);
},
[Math.min(state, 4)],
);
return state;
}
const el = document.createElement('div');
act(() => {
ReactDOM.unstable_createRoot(el).render(<App />);
});
expect(el.innerHTML).toBe('5');
});
});
});
4 changes: 2 additions & 2 deletions packages/react-dom/src/client/ReactDOM.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
getPublicRootInstance,
findHostInstance,
findHostInstanceWithWarning,
flushPassiveEffects,
hasPendingEffects,
} from 'react-reconciler/inline.dom';
import {createPortal as createPortalImpl} from 'shared/ReactPortal';
import {canUseDOM} from 'shared/ExecutionEnvironment';
Expand Down Expand Up @@ -821,7 +821,7 @@ const ReactDOM: Object = {
restoreStateIfNeeded,
dispatchEvent,
runEventsInBatch,
flushPassiveEffects,
hasPendingEffects,
],
},
};
Expand Down
2 changes: 1 addition & 1 deletion packages/react-dom/src/test-utils/ReactTestUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const [
dispatchEvent,
runEventsInBatch,
// eslint-disable-next-line no-unused-vars
flushPassiveEffects,
hasPendingEffects,
] = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;

function Event(suffix) {}
Expand Down
9 changes: 5 additions & 4 deletions packages/react-dom/src/test-utils/ReactTestUtilsAct.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import warningWithoutStack from 'shared/warningWithoutStack';
import ReactDOM from 'react-dom';
import ReactSharedInternals from 'shared/ReactSharedInternals';
import enqueueTask from 'shared/enqueueTask';
import * as Scheduler from 'scheduler';

// Keep in sync with ReactDOMUnstableNativeDependencies.js
// ReactDOM.js, and ReactTestUtils.js:
Expand All @@ -30,7 +31,7 @@ const [
dispatchEvent,
runEventsInBatch,
/* eslint-enable no-unused-vars */
flushPassiveEffects,
hasPendingEffects,
] = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;

const batchedUpdates = ReactDOM.unstable_batchedUpdates;
Expand All @@ -46,9 +47,9 @@ let actingUpdatesScopeDepth = 0;

function flushEffectsAndMicroTasks(onDone: (err: ?Error) => void) {
try {
flushPassiveEffects();
Scheduler.unstable_flushWithoutYielding();
enqueueTask(() => {
if (flushPassiveEffects()) {
if (hasPendingEffects()) {
flushEffectsAndMicroTasks(onDone);
} else {
onDone();
Expand Down Expand Up @@ -147,7 +148,7 @@ function act(callback: () => Thenable) {

// flush effects until none remain, and cleanup
try {
while (flushPassiveEffects()) {}
Scheduler.unstable_flushWithoutYielding();
onDone();
} catch (err) {
onDone();
Expand Down
10 changes: 6 additions & 4 deletions packages/react-noop-renderer/src/createReactNoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -645,18 +645,20 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
const roots = new Map();
const DEFAULT_ROOT_ID = '<default>';

const {flushPassiveEffects, batchedUpdates} = NoopRenderer;
const {hasPendingEffects, batchedUpdates} = NoopRenderer;

// this act() implementation should be exactly the same in
// ReactTestUtilsAct.js, ReactTestRendererAct.js, createReactNoop.js

// we track the 'depth' of the act() calls with this counter,
// so we can tell if any async act() calls try to run in parallel.
let actingUpdatesScopeDepth = 0;

function flushEffectsAndMicroTasks(onDone: (err: ?Error) => void) {
try {
flushPassiveEffects();
Scheduler.unstable_flushWithoutYielding();
enqueueTask(() => {
if (flushPassiveEffects()) {
if (hasPendingEffects()) {
flushEffectsAndMicroTasks(onDone);
} else {
onDone();
Expand Down Expand Up @@ -755,7 +757,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {

// flush effects until none remain, and cleanup
try {
while (flushPassiveEffects()) {}
Scheduler.unstable_flushWithoutYielding();
onDone();
} catch (err) {
onDone();
Expand Down
2 changes: 2 additions & 0 deletions packages/react-reconciler/src/ReactFiberReconciler.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
interactiveUpdates,
flushInteractiveUpdates,
flushPassiveEffects,
hasPendingEffects,
} from './ReactFiberScheduler';
import {createUpdate, enqueueUpdate} from './ReactUpdateQueue';
import ReactFiberInstrumentation from './ReactFiberInstrumentation';
Expand Down Expand Up @@ -309,6 +310,7 @@ export {
flushControlled,
flushSync,
flushPassiveEffects,
hasPendingEffects,
};

export function getPublicRootInstance(
Expand Down
6 changes: 4 additions & 2 deletions packages/react-reconciler/src/ReactFiberScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -1604,7 +1604,7 @@ function commitLayoutEffects(

export function flushPassiveEffects() {
if (rootWithPendingPassiveEffects === null) {
return false;
return;
}
const root = rootWithPendingPassiveEffects;
const expirationTime = pendingPassiveEffectsExpirationTime;
Expand Down Expand Up @@ -1661,8 +1661,10 @@ export function flushPassiveEffects() {
// exceeds the limit, we'll fire a warning.
nestedPassiveUpdateCount =
rootWithPendingPassiveEffects === null ? 0 : nestedPassiveUpdateCount + 1;
}

return true;
export function hasPendingEffects() {
return rootWithPendingPassiveEffects !== null;
}

export function isAlreadyFailedLegacyErrorBoundary(instance: mixed): boolean {
Expand Down
Loading