Skip to content

Decouple update priority tracking from Scheduler package #19121

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Jul 6, 2020
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
dc66f1b
Initial currentLanePriority implementation
rickhanlonii Jun 12, 2020
dd82bcd
Minor updates from review
rickhanlonii Jun 12, 2020
4404ed2
Fix typos and enable flag
rickhanlonii Jun 16, 2020
a029969
Fix feature flags and lint
rickhanlonii Jun 16, 2020
815c4ed
Fix simple event tests by switching to withSuspenseConfig
rickhanlonii Jun 19, 2020
c454bda
Don't lower the priority of setPending in startTransition below Input…
rickhanlonii Jun 19, 2020
6fe9d23
Move currentUpdateLanePriority in commit root into the first effect b…
rickhanlonii Jun 19, 2020
7d5c251
Refactor requestUpdateLane to log for priority mismatches
rickhanlonii Jun 19, 2020
79fdca3
Fix four tests by adding ReactDOM.unstable_runWithPriority
rickhanlonii Jun 20, 2020
a238e2f
Fix partial hydration when using update lane priority
rickhanlonii Jun 20, 2020
2dcd2aa
Fix partial hydration when using update lane priority
rickhanlonii Jun 20, 2020
db5f479
Rename feature flag and only log for now
rickhanlonii Jun 26, 2020
fbbddcf
Move unstable_runWithPriority to ReactFiberReconciler
rickhanlonii Jun 26, 2020
93eca31
Add unstable_runWithPriority to ReactNoopPersistent too
rickhanlonii Jun 26, 2020
ce0c4a6
Bug fixes and performance improvements
rickhanlonii Jun 26, 2020
6e7fbbe
Remove higherLanePriority from ReactDOMEventReplaying.js
rickhanlonii Jun 30, 2020
a2445c2
Change warning implementation and startTransition update lane priority
rickhanlonii Jun 30, 2020
f3cb0d8
Inject reconciler functions to avoid importing src/
rickhanlonii Jun 30, 2020
866c5ba
Initial currentLanePriority implementation
rickhanlonii Jun 12, 2020
d132425
Minor updates from review
rickhanlonii Jun 12, 2020
0844f04
Fix typos and enable flag
rickhanlonii Jun 16, 2020
e317e3a
Fix feature flags and lint
rickhanlonii Jun 16, 2020
9f472fb
Fix simple event tests by switching to withSuspenseConfig
rickhanlonii Jun 19, 2020
8f58f02
Don't lower the priority of setPending in startTransition below Input…
rickhanlonii Jun 19, 2020
1930096
Move currentUpdateLanePriority in commit root into the first effect b…
rickhanlonii Jun 19, 2020
6b500da
Refactor requestUpdateLane to log for priority mismatches
rickhanlonii Jun 19, 2020
863ce17
Fix four tests by adding ReactDOM.unstable_runWithPriority
rickhanlonii Jun 20, 2020
27adc13
Fix partial hydration when using update lane priority
rickhanlonii Jun 20, 2020
c6c760d
Fix partial hydration when using update lane priority
rickhanlonii Jun 20, 2020
28a889f
Rename feature flag and only log for now
rickhanlonii Jun 26, 2020
9c71654
Move unstable_runWithPriority to ReactFiberReconciler
rickhanlonii Jun 26, 2020
5802d55
Bug fixes and performance improvements
rickhanlonii Jun 26, 2020
0d9812c
Remove higherLanePriority from ReactDOMEventReplaying.js
rickhanlonii Jun 30, 2020
383eb73
Change warning implementation and startTransition update lane priority
rickhanlonii Jun 30, 2020
23eb05a
Inject reconciler functions to avoid importing src/
rickhanlonii Jun 30, 2020
4294152
Fixes from bad rebase
rickhanlonii Jul 6, 2020
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
1 change: 1 addition & 0 deletions packages/react-dom/index.classic.fb.js
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ export {
createBlockingRoot as unstable_createBlockingRoot,
unstable_flushControlled,
unstable_scheduleHydration,
unstable_runWithPriority,
unstable_renderSubtreeIntoContainer,
unstable_createPortal,
unstable_createEventHandle,
2 changes: 2 additions & 0 deletions packages/react-dom/index.experimental.js
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ export {
createBlockingRoot as unstable_createBlockingRoot,
unstable_flushControlled,
unstable_scheduleHydration,
// DO NOT USE: Temporarily exposing this to migrate off of Scheduler.runWithPriority.
unstable_runWithPriority,
// Disabled behind disableUnstableRenderSubtreeIntoContainer
unstable_renderSubtreeIntoContainer,
// Disabled behind disableUnstableCreatePortal
1 change: 1 addition & 0 deletions packages/react-dom/index.js
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ export {
createBlockingRoot as unstable_createBlockingRoot,
unstable_flushControlled,
unstable_scheduleHydration,
unstable_runWithPriority,
unstable_renderSubtreeIntoContainer,
unstable_createPortal,
unstable_createEventHandle,
1 change: 1 addition & 0 deletions packages/react-dom/index.modern.fb.js
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ export {
createBlockingRoot as unstable_createBlockingRoot,
unstable_flushControlled,
unstable_scheduleHydration,
unstable_runWithPriority,
unstable_createEventHandle,
unstable_isNewReconciler,
} from './src/client/ReactDOM';
9 changes: 9 additions & 0 deletions packages/react-dom/src/client/ReactDOM.js
Original file line number Diff line number Diff line change
@@ -35,6 +35,8 @@ import {
attemptUserBlockingHydration,
attemptContinuousHydration,
attemptHydrationAtCurrentPriority,
runWithPriority,
getCurrentUpdatePriority,
} from 'react-reconciler/src/ReactFiberReconciler';
import {createPortal as createPortalImpl} from 'react-reconciler/src/ReactPortal';
import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -58,6 +60,8 @@ import {
setAttemptContinuousHydration,
setAttemptHydrationAtCurrentPriority,
queueExplicitHydrationTarget,
setGetCurrentUpdatePriority,
setAttemptHydrationAtPriority,
} from '../events/ReactDOMEventReplaying';
import {setBatchingImplementation} from '../events/ReactDOMUpdateBatching';
import {
@@ -70,6 +74,8 @@ setAttemptSynchronousHydration(attemptSynchronousHydration);
setAttemptUserBlockingHydration(attemptUserBlockingHydration);
setAttemptContinuousHydration(attemptContinuousHydration);
setAttemptHydrationAtCurrentPriority(attemptHydrationAtCurrentPriority);
setGetCurrentUpdatePriority(getCurrentUpdatePriority);
setAttemptHydrationAtPriority(runWithPriority);

let didWarnAboutUnstableCreatePortal = false;
let didWarnAboutUnstableRenderSubtreeIntoContainer = false;
@@ -205,6 +211,9 @@ export {
unstable_createPortal,
// enableCreateEventHandleAPI
createEventHandle as unstable_createEventHandle,
// TODO: Remove this once callers migrate to alternatives.
// This should only be used by React internals.
runWithPriority as unstable_runWithPriority,
};

const foundDevTools = injectIntoDevTools({
38 changes: 32 additions & 6 deletions packages/react-dom/src/events/ReactDOMEventReplaying.js
Original file line number Diff line number Diff line change
@@ -12,7 +12,10 @@ import type {Container, SuspenseInstance} from '../client/ReactDOMHostConfig';
import type {DOMTopLevelEventType} from '../events/TopLevelEventTypes';
import type {ElementListenerMap} from '../client/ReactDOMComponentTree';
import type {EventSystemFlags} from './EventSystemFlags';
import type {FiberRoot} from 'react-reconciler/src/ReactInternalTypes';
import type {
FiberRoot,
ReactPriorityLevel,
} from 'react-reconciler/src/ReactInternalTypes';

import {
enableDeprecatedFlareAPI,
@@ -64,6 +67,23 @@ export function setAttemptHydrationAtCurrentPriority(
attemptHydrationAtCurrentPriority = fn;
}

let getCurrentUpdatePriority: () => ReactPriorityLevel;

export function setGetCurrentUpdatePriority(fn: () => ReactPriorityLevel) {
getCurrentUpdatePriority = fn;
}

let attemptHydrationAtPriority: <T>(
priority: ReactPriorityLevel,
fn: () => T,
) => T;

export function setAttemptHydrationAtPriority(
fn: <T>(priority: ReactPriorityLevel, fn: () => T) => T,
) {
attemptHydrationAtPriority = fn;
}

// TODO: Upgrade this definition once we're on a newer version of Flow that
// has this definition built-in.
type PointerEvent = Event & {
@@ -147,6 +167,7 @@ type QueuedHydrationTarget = {|
blockedOn: null | Container | SuspenseInstance,
target: Node,
priority: number,
lanePriority: ReactPriorityLevel,
|};
const queuedExplicitHydrationTargets: Array<QueuedHydrationTarget> = [];

@@ -508,9 +529,12 @@ function attemptExplicitHydrationTarget(
// We're blocked on hydrating this boundary.
// Increase its priority.
queuedTarget.blockedOn = instance;
runWithPriority(queuedTarget.priority, () => {
attemptHydrationAtCurrentPriority(nearestMounted);
attemptHydrationAtPriority(queuedTarget.lanePriority, () => {
runWithPriority(queuedTarget.priority, () => {
attemptHydrationAtCurrentPriority(nearestMounted);
});
});

return;
}
} else if (tag === HostRoot) {
@@ -529,15 +553,17 @@ function attemptExplicitHydrationTarget(

export function queueExplicitHydrationTarget(target: Node): void {
if (enableSelectiveHydration) {
const priority = getCurrentPriorityLevel();
const schedulerPriority = getCurrentPriorityLevel();
const updateLanePriority = getCurrentUpdatePriority();
const queuedTarget: QueuedHydrationTarget = {
blockedOn: null,
target: target,
priority: priority,
priority: schedulerPriority,
lanePriority: updateLanePriority,
};
let i = 0;
for (; i < queuedExplicitHydrationTargets.length; i++) {
if (priority <= queuedExplicitHydrationTargets[i].priority) {
if (schedulerPriority <= queuedExplicitHydrationTargets[i].priority) {
break;
}
}
Original file line number Diff line number Diff line change
@@ -231,6 +231,8 @@ describe('SimpleEventPlugin', function() {
describe('interactive events, in concurrent mode', () => {
beforeEach(() => {
jest.resetModules();

React = require('react');
ReactDOM = require('react-dom');
Scheduler = require('scheduler');
});
@@ -377,11 +379,14 @@ describe('SimpleEventPlugin', function() {
<button
ref={el => (button = el)}
onClick={() => {
Scheduler.unstable_next(() => {
this.setState(state => ({
lowPriCount: state.lowPriCount + 1,
}));
});
React.unstable_withSuspenseConfig(
() => {
this.setState(state => ({
lowPriCount: state.lowPriCount + 1,
}));
},
{timeoutMs: 5000},
);
}}>
{text}
</button>
3 changes: 3 additions & 0 deletions packages/react-noop-renderer/src/ReactNoop.js
Original file line number Diff line number Diff line change
@@ -47,6 +47,9 @@ export const {
act,
dumpTree,
getRoot,
// TODO: Remove this once callers migrate to alternatives.
// This should only be used by React internals.
unstable_runWithPriority,
} = createReactNoop(
ReactFiberReconciler, // reconciler
true, // useMutation
3 changes: 3 additions & 0 deletions packages/react-noop-renderer/src/ReactNoopPersistent.js
Original file line number Diff line number Diff line change
@@ -47,6 +47,9 @@ export const {
act,
dumpTree,
getRoot,
// TODO: Remove this once callers migrate to alternatives.
// This should only be used by React internals.
unstable_runWithPriority,
} = createReactNoop(
ReactFiberReconciler, // reconciler
false, // useMutation
2 changes: 2 additions & 0 deletions packages/react-noop-renderer/src/createReactNoop.js
Original file line number Diff line number Diff line change
@@ -954,6 +954,8 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
return Scheduler.unstable_flushExpired();
},

unstable_runWithPriority: NoopRenderer.runWithPriority,

batchedUpdates: NoopRenderer.batchedUpdates,

deferredUpdates: NoopRenderer.deferredUpdates,
14 changes: 14 additions & 0 deletions packages/react-reconciler/src/ReactFiberHooks.new.js
Original file line number Diff line number Diff line change
@@ -30,11 +30,16 @@ import {NoMode, BlockingMode} from './ReactTypeOfMode';
import {
NoLane,
NoLanes,
InputContinuousLanePriority,
isSubsetOfLanes,
mergeLanes,
removeLanes,
markRootEntangled,
markRootMutableRead,
getCurrentUpdateLanePriority,
setCurrentUpdateLanePriority,
higherLanePriority,
DefaultLanePriority,
} from './ReactFiberLane';
import {readContext} from './ReactFiberNewContext.new';
import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.new';
@@ -1498,12 +1503,20 @@ function rerenderDeferredValue<T>(

function startTransition(setPending, config, callback) {
const priorityLevel = getCurrentPriorityLevel();
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(
higherLanePriority(previousLanePriority, InputContinuousLanePriority),
);
runWithPriority(
priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel,
() => {
setPending(true);
},
);

// If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
setCurrentUpdateLanePriority(DefaultLanePriority);

runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => {
@@ -1513,6 +1526,7 @@ function startTransition(setPending, config, callback) {
setPending(false);
callback();
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
ReactCurrentBatchConfig.suspense = previousConfig;
}
},
14 changes: 14 additions & 0 deletions packages/react-reconciler/src/ReactFiberHooks.old.js
Original file line number Diff line number Diff line change
@@ -33,11 +33,16 @@ import {NoMode, BlockingMode, DebugTracingMode} from './ReactTypeOfMode';
import {
NoLane,
NoLanes,
InputContinuousLanePriority,
isSubsetOfLanes,
mergeLanes,
removeLanes,
markRootEntangled,
markRootMutableRead,
getCurrentUpdateLanePriority,
setCurrentUpdateLanePriority,
higherLanePriority,
DefaultLanePriority,
} from './ReactFiberLane';
import {readContext} from './ReactFiberNewContext.old';
import {createDeprecatedResponderListener} from './ReactFiberDeprecatedEvents.old';
@@ -1502,12 +1507,20 @@ function rerenderDeferredValue<T>(

function startTransition(setPending, config, callback) {
const priorityLevel = getCurrentPriorityLevel();
const previousLanePriority = getCurrentUpdateLanePriority();
setCurrentUpdateLanePriority(
higherLanePriority(previousLanePriority, InputContinuousLanePriority),
);
runWithPriority(
priorityLevel < UserBlockingPriority ? UserBlockingPriority : priorityLevel,
() => {
setPending(true);
},
);

// If there's no SuspenseConfig set, we'll use the DefaultLanePriority for this transition.
setCurrentUpdateLanePriority(DefaultLanePriority);

runWithPriority(
priorityLevel > NormalPriority ? NormalPriority : priorityLevel,
() => {
@@ -1517,6 +1530,7 @@ function startTransition(setPending, config, callback) {
setPending(false);
callback();
} finally {
setCurrentUpdateLanePriority(previousLanePriority);
ReactCurrentBatchConfig.suspense = previousConfig;
}
},
21 changes: 19 additions & 2 deletions packages/react-reconciler/src/ReactFiberLane.js
Original file line number Diff line number Diff line change
@@ -49,10 +49,10 @@ const InputDiscreteHydrationLanePriority: LanePriority = 14;
export const InputDiscreteLanePriority: LanePriority = 13;

const InputContinuousHydrationLanePriority: LanePriority = 12;
const InputContinuousLanePriority: LanePriority = 11;
export const InputContinuousLanePriority: LanePriority = 11;

const DefaultHydrationLanePriority: LanePriority = 10;
const DefaultLanePriority: LanePriority = 9;
export const DefaultLanePriority: LanePriority = 9;

const TransitionShortHydrationLanePriority: LanePriority = 8;
export const TransitionShortLanePriority: LanePriority = 7;
@@ -120,6 +120,16 @@ export const OffscreenLane: Lane = /* */ 0b1000000000000000000

export const NoTimestamp = -1;

let currentUpdateLanePriority: LanePriority = NoLanePriority;

export function getCurrentUpdateLanePriority(): LanePriority {
return currentUpdateLanePriority;
}

export function setCurrentUpdateLanePriority(newLanePriority: LanePriority) {
currentUpdateLanePriority = newLanePriority;
}

// "Registers" used to "return" multiple values
// Used by getHighestPriorityLanes and getNextLanes:
let return_highestLanePriority: LanePriority = DefaultLanePriority;
@@ -651,6 +661,13 @@ export function higherPriorityLane(a: Lane, b: Lane) {
return a !== NoLane && a < b ? a : b;
}

export function higherLanePriority(
a: LanePriority,
b: LanePriority,
): LanePriority {
return a !== NoLanePriority && a > b ? a : b;
}

export function createLaneMap<T>(initial: T): LaneMap<T> {
return new Array(TotalLanes).fill(initial);
}
10 changes: 10 additions & 0 deletions packages/react-reconciler/src/ReactFiberReconciler.js
Original file line number Diff line number Diff line change
@@ -50,6 +50,8 @@ import {
focusWithin as focusWithin_old,
observeVisibleRects as observeVisibleRects_old,
registerMutableSourceForHydration as registerMutableSourceForHydration_old,
runWithPriority as runWithPriority_old,
getCurrentUpdatePriority as getCurrentUpdatePriority_old,
} from './ReactFiberReconciler.old';

import {
@@ -88,6 +90,8 @@ import {
focusWithin as focusWithin_new,
observeVisibleRects as observeVisibleRects_new,
registerMutableSourceForHydration as registerMutableSourceForHydration_new,
runWithPriority as runWithPriority_new,
getCurrentUpdatePriority as getCurrentUpdatePriority_new,
} from './ReactFiberReconciler.new';

export const createContainer = enableNewReconciler
@@ -139,6 +143,9 @@ export const attemptContinuousHydration = enableNewReconciler
export const attemptHydrationAtCurrentPriority = enableNewReconciler
? attemptHydrationAtCurrentPriority_new
: attemptHydrationAtCurrentPriority_old;
export const getCurrentUpdatePriority = enableNewReconciler
? getCurrentUpdatePriority_new
: getCurrentUpdatePriority_old;
export const findHostInstance = enableNewReconciler
? findHostInstance_new
: findHostInstance_old;
@@ -194,3 +201,6 @@ export const observeVisibleRects = enableNewReconciler
export const registerMutableSourceForHydration = enableNewReconciler
? registerMutableSourceForHydration_new
: registerMutableSourceForHydration_old;
export const runWithPriority = enableNewReconciler
? runWithPriority_new
: runWithPriority_old;
Loading