Skip to content

Commit d4cd317

Browse files
committed
Use global flag to optimize checking context dependencies
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.
1 parent 4f7dbcf commit d4cd317

File tree

1 file changed

+25
-7
lines changed

1 file changed

+25
-7
lines changed

packages/react-reconciler/src/ReactFiberNewContext.js

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {ContextProvider} from 'shared/ReactTypeOfWork';
2828

2929
import invariant from 'shared/invariant';
3030

31-
const providerCursor: StackCursor<Fiber | null> = createCursor(null);
31+
const someContextChangedCursor: StackCursor<boolean> = createCursor(false);
3232
const valueCursor: StackCursor<mixed> = createCursor(null);
3333
const changedBitsCursor: StackCursor<number> = createCursor(0);
3434

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

5352
context._currentValue = providerFiber.pendingProps.value;
54-
context._changedBits = providerFiber.stateNode;
53+
const changedBits = (context._changedBits = providerFiber.stateNode);
54+
55+
push(
56+
someContextChangedCursor,
57+
someContextChangedCursor.current || changedBits !== 0,
58+
providerFiber,
59+
);
60+
5561
if (__DEV__) {
5662
warning(
5763
context._currentRenderer === undefined ||
@@ -65,10 +71,16 @@ export function pushProvider(providerFiber: Fiber): void {
6571
} else {
6672
push(changedBitsCursor, context._changedBits2, providerFiber);
6773
push(valueCursor, context._currentValue2, providerFiber);
68-
push(providerCursor, providerFiber, providerFiber);
6974

7075
context._currentValue2 = providerFiber.pendingProps.value;
71-
context._changedBits2 = providerFiber.stateNode;
76+
const changedBits = (context._changedBits2 = providerFiber.stateNode);
77+
78+
push(
79+
someContextChangedCursor,
80+
someContextChangedCursor.current || changedBits !== 0,
81+
providerFiber,
82+
);
83+
7284
if (__DEV__) {
7385
warning(
7486
context._currentRenderer2 === undefined ||
@@ -86,7 +98,7 @@ export function popProvider(providerFiber: Fiber): void {
8698
const changedBits = changedBitsCursor.current;
8799
const currentValue = valueCursor.current;
88100

89-
pop(providerCursor, providerFiber);
101+
pop(someContextChangedCursor, providerFiber);
90102
pop(valueCursor, providerFiber);
91103
pop(changedBitsCursor, providerFiber);
92104

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

222+
// Check the global flag to see if there are any pending contexts. This is
223+
// optimizes for the normal case where no contexts have updated at all.
224+
if (someContextChangedCursor.current === false) {
225+
return false;
226+
}
227+
228+
let hasPendingContext = false;
210229
// Iterate through the context dependencies and see if there were any
211230
// changes. If so, continue propagating the context change by scanning
212231
// the child subtree.
213232
let dependency = memoizedFirstContextDependency;
214-
let hasPendingContext = false;
215233
do {
216234
const context = dependency.context;
217235
const changedBits = isPrimaryRenderer

0 commit comments

Comments
 (0)