Skip to content

Commit

Permalink
Add unstable_concurrentUpdatesByDefault
Browse files Browse the repository at this point in the history
  • Loading branch information
rickhanlonii committed Apr 10, 2021
1 parent 933880b commit b820aed
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 10 deletions.
31 changes: 31 additions & 0 deletions packages/react-dom/src/__tests__/ReactDOMRoot-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ let React = require('react');
let ReactDOM = require('react-dom');
let ReactDOMServer = require('react-dom/server');
let Scheduler = require('scheduler');
let act;

describe('ReactDOMRoot', () => {
let container;
Expand All @@ -24,6 +25,7 @@ describe('ReactDOMRoot', () => {
ReactDOM = require('react-dom');
ReactDOMServer = require('react-dom/server');
Scheduler = require('scheduler');
act = require('react-dom/test-utils').unstable_concurrentAct;
});

if (!__EXPERIMENTAL__) {
Expand Down Expand Up @@ -316,4 +318,33 @@ describe('ReactDOMRoot', () => {
{withoutStack: true},
);
});

// @gate experimental
it('opts-in to concurrent default updates', async () => {
const root = ReactDOM.unstable_createRoot(container, {
unstable_concurrentUpdatesByDefault: true,
});

function Foo({value}) {
Scheduler.unstable_yieldValue(value);
return <div>{value}</div>;
}

await act(async () => {
root.render(<Foo value="a" />);
});

expect(container.textContent).toEqual('a');

await act(async () => {
root.render(<Foo value="b" />);

expect(Scheduler).toHaveYielded(['a']);
expect(container.textContent).toEqual('a');

expect(Scheduler).toFlushAndYieldThrough(['b']);
expect(container.textContent).toEqual('a');
});
expect(container.textContent).toEqual('b');
});
});
6 changes: 6 additions & 0 deletions packages/react-dom/src/client/ReactDOMRoot.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type RootOptions = {
...
},
unstable_strictModeLevel?: number,
unstable_concurrentUpdatesByDefault?: boolean,
...
};

Expand Down Expand Up @@ -125,13 +126,18 @@ function createRootImpl(
options != null && options.unstable_strictModeLevel != null
? options.unstable_strictModeLevel
: null;
const concurrentUpdatesByDefaultOverride =
options != null && options.unstable_concurrentUpdatesByDefault != null
? options.unstable_concurrentUpdatesByDefault
: null;

const root = createContainer(
container,
tag,
hydrate,
hydrationCallbacks,
strictModeLevelOverride,
concurrentUpdatesByDefaultOverride,
);
markContainerAsRoot(root.current, container);

Expand Down
5 changes: 5 additions & 0 deletions packages/react-reconciler/src/ReactFiber.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
ProfileMode,
StrictLegacyMode,
StrictEffectsMode,
ConcurrentUpdatesByDefaultMode,
} from './ReactTypeOfMode';
import {
REACT_FORWARD_REF_TYPE,
Expand Down Expand Up @@ -420,6 +421,7 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
export function createHostRootFiber(
tag: RootTag,
strictModeLevelOverride: null | number,
concurrentUpdatesByDefaultOverride: null | boolean,
): Fiber {
let mode;
if (tag === ConcurrentRoot) {
Expand All @@ -440,6 +442,9 @@ export function createHostRootFiber(
mode |= StrictLegacyMode;
}
}
if (concurrentUpdatesByDefaultOverride) {
mode |= ConcurrentUpdatesByDefaultMode;
}
} else {
mode = NoMode;
}
Expand Down
5 changes: 5 additions & 0 deletions packages/react-reconciler/src/ReactFiber.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
ProfileMode,
StrictLegacyMode,
StrictEffectsMode,
ConcurrentUpdatesByDefaultMode,
} from './ReactTypeOfMode';
import {
REACT_FORWARD_REF_TYPE,
Expand Down Expand Up @@ -420,6 +421,7 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
export function createHostRootFiber(
tag: RootTag,
strictModeLevelOverride: null | number,
concurrentUpdatesByDefaultOverride: null | boolean,
): Fiber {
let mode;
if (tag === ConcurrentRoot) {
Expand All @@ -440,6 +442,9 @@ export function createHostRootFiber(
mode |= StrictLegacyMode;
}
}
if (concurrentUpdatesByDefaultOverride) {
mode |= ConcurrentUpdatesByDefaultMode;
}
} else {
mode = NoMode;
}
Expand Down
2 changes: 2 additions & 0 deletions packages/react-reconciler/src/ReactFiberReconciler.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,15 @@ export function createContainer(
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
strictModeLevelOverride: null | number,
concurrentUpdatesByDefaultOverride: null | boolean,
): OpaqueRoot {
return createFiberRoot(
containerInfo,
tag,
hydrate,
hydrationCallbacks,
strictModeLevelOverride,
concurrentUpdatesByDefaultOverride,
);
}

Expand Down
2 changes: 2 additions & 0 deletions packages/react-reconciler/src/ReactFiberReconciler.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,15 @@ export function createContainer(
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
strictModeLevelOverride: null | number,
concurrentUpdatesByDefaultOverride: null | boolean,
): OpaqueRoot {
return createFiberRoot(
containerInfo,
tag,
hydrate,
hydrationCallbacks,
strictModeLevelOverride,
concurrentUpdatesByDefaultOverride,
);
}

Expand Down
7 changes: 6 additions & 1 deletion packages/react-reconciler/src/ReactFiberRoot.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export function createFiberRoot(
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
strictModeLevelOverride: null | number,
concurrentUpdatesByDefaultOverride: null | boolean,
): FiberRoot {
const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
if (enableSuspenseCallback) {
Expand All @@ -113,7 +114,11 @@ export function createFiberRoot(

// Cyclic construction. This cheats the type system right now because
// stateNode is any.
const uninitializedFiber = createHostRootFiber(tag, strictModeLevelOverride);
const uninitializedFiber = createHostRootFiber(
tag,
strictModeLevelOverride,
concurrentUpdatesByDefaultOverride,
);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;

Expand Down
7 changes: 6 additions & 1 deletion packages/react-reconciler/src/ReactFiberRoot.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ export function createFiberRoot(
hydrate: boolean,
hydrationCallbacks: null | SuspenseHydrationCallbacks,
strictModeLevelOverride: null | number,
concurrentUpdatesByDefaultOverride: null | boolean,
): FiberRoot {
const root: FiberRoot = (new FiberRootNode(containerInfo, tag, hydrate): any);
if (enableSuspenseCallback) {
Expand All @@ -113,7 +114,11 @@ export function createFiberRoot(

// Cyclic construction. This cheats the type system right now because
// stateNode is any.
const uninitializedFiber = createHostRootFiber(tag, strictModeLevelOverride);
const uninitializedFiber = createHostRootFiber(
tag,
strictModeLevelOverride,
concurrentUpdatesByDefaultOverride,
);
root.current = uninitializedFiber;
uninitializedFiber.stateNode = root;

Expand Down
10 changes: 9 additions & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ import {
StrictLegacyMode,
ProfileMode,
ConcurrentMode,
ConcurrentUpdatesByDefaultMode,
} from './ReactTypeOfMode';
import {
HostRoot,
Expand Down Expand Up @@ -440,6 +441,7 @@ export function requestUpdateLane(fiber: Fiber): Lane {
if (updateLane !== NoLane) {
if (
enableSyncDefaultUpdates &&
(mode & ConcurrentUpdatesByDefaultMode) === NoMode &&
(updateLane === InputContinuousLane ||
updateLane === InputContinuousHydrationLane)
) {
Expand All @@ -457,6 +459,7 @@ export function requestUpdateLane(fiber: Fiber): Lane {
const eventLane: Lane = (getCurrentEventPriority(): any);
if (
enableSyncDefaultUpdates &&
(mode & ConcurrentUpdatesByDefaultMode) === NoMode &&
(eventLane === InputContinuousLane ||
eventLane === InputContinuousHydrationLane)
) {
Expand Down Expand Up @@ -716,6 +719,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
let newCallbackNode;
if (
enableSyncDefaultUpdates &&
(root.current.mode & ConcurrentUpdatesByDefaultMode) === NoMode &&
(newCallbackPriority === DefaultLane ||
newCallbackPriority === DefaultHydrationLane)
) {
Expand Down Expand Up @@ -1058,7 +1062,11 @@ function performSyncWorkOnRoot(root) {
const finishedWork: Fiber = (root.current.alternate: any);
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
if (enableSyncDefaultUpdates && !includesSomeLane(lanes, SyncLane)) {
if (
enableSyncDefaultUpdates &&
(root.current.mode & ConcurrentUpdatesByDefaultMode) === NoMode &&
!includesSomeLane(lanes, SyncLane)
) {
finishConcurrentRender(root, exitStatus, lanes);
} else {
commitRoot(root);
Expand Down
10 changes: 9 additions & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ import {
StrictLegacyMode,
ProfileMode,
ConcurrentMode,
ConcurrentUpdatesByDefaultMode,
} from './ReactTypeOfMode';
import {
HostRoot,
Expand Down Expand Up @@ -440,6 +441,7 @@ export function requestUpdateLane(fiber: Fiber): Lane {
if (updateLane !== NoLane) {
if (
enableSyncDefaultUpdates &&
(mode & ConcurrentUpdatesByDefaultMode) === NoMode &&
(updateLane === InputContinuousLane ||
updateLane === InputContinuousHydrationLane)
) {
Expand All @@ -457,6 +459,7 @@ export function requestUpdateLane(fiber: Fiber): Lane {
const eventLane: Lane = (getCurrentEventPriority(): any);
if (
enableSyncDefaultUpdates &&
(mode & ConcurrentUpdatesByDefaultMode) === NoMode &&
(eventLane === InputContinuousLane ||
eventLane === InputContinuousHydrationLane)
) {
Expand Down Expand Up @@ -716,6 +719,7 @@ function ensureRootIsScheduled(root: FiberRoot, currentTime: number) {
let newCallbackNode;
if (
enableSyncDefaultUpdates &&
(root.current.mode & ConcurrentUpdatesByDefaultMode) === NoMode &&
(newCallbackPriority === DefaultLane ||
newCallbackPriority === DefaultHydrationLane)
) {
Expand Down Expand Up @@ -1058,7 +1062,11 @@ function performSyncWorkOnRoot(root) {
const finishedWork: Fiber = (root.current.alternate: any);
root.finishedWork = finishedWork;
root.finishedLanes = lanes;
if (enableSyncDefaultUpdates && !includesSomeLane(lanes, SyncLane)) {
if (
enableSyncDefaultUpdates &&
(root.current.mode & ConcurrentUpdatesByDefaultMode) === NoMode &&
!includesSomeLane(lanes, SyncLane)
) {
finishConcurrentRender(root, exitStatus, lanes);
} else {
commitRoot(root);
Expand Down
13 changes: 7 additions & 6 deletions packages/react-reconciler/src/ReactTypeOfMode.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@

export type TypeOfMode = number;

export const NoMode = /* */ 0b000000;
export const NoMode = /* */ 0b000000;
// TODO: Remove ConcurrentMode by reading from the root tag instead
export const ConcurrentMode = /* */ 0b000001;
export const ProfileMode = /* */ 0b000010;
export const DebugTracingMode = /* */ 0b000100;
export const StrictLegacyMode = /* */ 0b001000;
export const StrictEffectsMode = /* */ 0b010000;
export const ConcurrentMode = /* */ 0b000001;
export const ProfileMode = /* */ 0b000010;
export const DebugTracingMode = /* */ 0b000100;
export const StrictLegacyMode = /* */ 0b001000;
export const StrictEffectsMode = /* */ 0b010000;
export const ConcurrentUpdatesByDefaultMode = /* */ 0b100000;
6 changes: 6 additions & 0 deletions packages/react-test-renderer/src/ReactTestRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type TestRendererOptions = {
createNodeMock: (element: React$Element<any>) => any,
unstable_isConcurrent: boolean,
unstable_strictModeLevel: number,
unstable_concurrentUpdatesByDefault: boolean,
...
};

Expand Down Expand Up @@ -436,6 +437,7 @@ function create(element: React$Element<any>, options: TestRendererOptions) {
let createNodeMock = defaultTestOptions.createNodeMock;
let isConcurrent = false;
let strictModeLevel = null;
let concurrentUpdatesByDefault = null;
if (typeof options === 'object' && options !== null) {
if (typeof options.createNodeMock === 'function') {
createNodeMock = options.createNodeMock;
Expand All @@ -446,6 +448,9 @@ function create(element: React$Element<any>, options: TestRendererOptions) {
if (options.unstable_strictModeLevel !== undefined) {
strictModeLevel = options.unstable_strictModeLevel;
}
if (options.unstable_concurrentUpdatesByDefault !== undefined) {
concurrentUpdatesByDefault = options.unstable_concurrentUpdatesByDefault;
}
}
let container = {
children: [],
Expand All @@ -458,6 +463,7 @@ function create(element: React$Element<any>, options: TestRendererOptions) {
false,
null,
strictModeLevel,
concurrentUpdatesByDefault,
);
invariant(root != null, 'something went wrong');
updateContainer(element, root, null, null);
Expand Down

0 comments on commit b820aed

Please sign in to comment.