Skip to content

Commit

Permalink
Use global flag to optimize checking context dependencies
Browse files Browse the repository at this point in the history
Track whether *any* contexts have changed on the stack. If this flag is
false, we can skip checking any context dependencies. Since it's unusual
that more than one context updates within the same batch, this should
save us a lot of unnecessary checks.
  • Loading branch information
acdlite committed Jul 5, 2018
1 parent 4f7dbcf commit d4cd317
Showing 1 changed file with 25 additions and 7 deletions.
32 changes: 25 additions & 7 deletions packages/react-reconciler/src/ReactFiberNewContext.js
Expand Up @@ -28,7 +28,7 @@ import {ContextProvider} from 'shared/ReactTypeOfWork';

import invariant from 'shared/invariant';

const providerCursor: StackCursor<Fiber | null> = createCursor(null);
const someContextChangedCursor: StackCursor<boolean> = createCursor(false);
const valueCursor: StackCursor<mixed> = createCursor(null);
const changedBitsCursor: StackCursor<number> = createCursor(0);

Expand All @@ -48,10 +48,16 @@ export function pushProvider(providerFiber: Fiber): void {
if (isPrimaryRenderer) {
push(changedBitsCursor, context._changedBits, providerFiber);
push(valueCursor, context._currentValue, providerFiber);
push(providerCursor, providerFiber, providerFiber);

context._currentValue = providerFiber.pendingProps.value;
context._changedBits = providerFiber.stateNode;
const changedBits = (context._changedBits = providerFiber.stateNode);

push(
someContextChangedCursor,
someContextChangedCursor.current || changedBits !== 0,
providerFiber,
);

if (__DEV__) {
warning(
context._currentRenderer === undefined ||
Expand All @@ -65,10 +71,16 @@ export function pushProvider(providerFiber: Fiber): void {
} else {
push(changedBitsCursor, context._changedBits2, providerFiber);
push(valueCursor, context._currentValue2, providerFiber);
push(providerCursor, providerFiber, providerFiber);

context._currentValue2 = providerFiber.pendingProps.value;
context._changedBits2 = providerFiber.stateNode;
const changedBits = (context._changedBits2 = providerFiber.stateNode);

push(
someContextChangedCursor,
someContextChangedCursor.current || changedBits !== 0,
providerFiber,
);

if (__DEV__) {
warning(
context._currentRenderer2 === undefined ||
Expand All @@ -86,7 +98,7 @@ export function popProvider(providerFiber: Fiber): void {
const changedBits = changedBitsCursor.current;
const currentValue = valueCursor.current;

pop(providerCursor, providerFiber);
pop(someContextChangedCursor, providerFiber);
pop(valueCursor, providerFiber);
pop(changedBitsCursor, providerFiber);

Expand Down Expand Up @@ -207,11 +219,17 @@ export function prepareToReadContext(
// Reset the work-in-progress list
workInProgress.firstContextDependency = null;

// Check the global flag to see if there are any pending contexts. This is
// optimizes for the normal case where no contexts have updated at all.
if (someContextChangedCursor.current === false) {
return false;
}

let hasPendingContext = false;
// Iterate through the context dependencies and see if there were any
// changes. If so, continue propagating the context change by scanning
// the child subtree.
let dependency = memoizedFirstContextDependency;
let hasPendingContext = false;
do {
const context = dependency.context;
const changedBits = isPrimaryRenderer
Expand Down

0 comments on commit d4cd317

Please sign in to comment.