Remove unnecessary branching from updateContextProvider (#13282)

This code had gotten unnecessarily complex after some recent changes.
Cleaned it up a bit.
This commit is contained in:
Andrew Clark
2018-07-27 13:42:17 -07:00
committed by GitHub
parent 840cb1a268
commit 2a2ef7e0fd
4 changed files with 54 additions and 75 deletions
+15 -69
View File
@@ -73,6 +73,7 @@ import {
propagateContextChange,
readContext,
prepareToReadContext,
calculateChangedBits,
} from './ReactFiberNewContext';
import {
markActualRenderTimeStarted,
@@ -824,88 +825,34 @@ function updateContextProvider(current, workInProgress, renderExpirationTime) {
// Initial render
changedBits = MAX_SIGNED_31_BIT_INT;
} else {
if (oldProps.value === newProps.value) {
const oldValue = oldProps.value;
changedBits = calculateChangedBits(context, newValue, oldValue);
if (changedBits === 0) {
// No change. Bailout early if children are the same.
if (
oldProps.children === newProps.children &&
!hasLegacyContextChanged()
) {
workInProgress.stateNode = 0;
pushProvider(workInProgress);
pushProvider(workInProgress, 0);
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderExpirationTime,
);
}
changedBits = 0;
} else {
const oldValue = oldProps.value;
// Use Object.is to compare the new context value to the old value.
// Inlined Object.is polyfill.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
if (
(oldValue === newValue &&
(oldValue !== 0 || 1 / oldValue === 1 / newValue)) ||
(oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare
) {
// No change. Bailout early if children are the same.
if (
oldProps.children === newProps.children &&
!hasLegacyContextChanged()
) {
workInProgress.stateNode = 0;
pushProvider(workInProgress);
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderExpirationTime,
);
}
changedBits = 0;
} else {
changedBits =
typeof context._calculateChangedBits === 'function'
? context._calculateChangedBits(oldValue, newValue)
: MAX_SIGNED_31_BIT_INT;
if (__DEV__) {
warning(
(changedBits & MAX_SIGNED_31_BIT_INT) === changedBits,
'calculateChangedBits: Expected the return value to be a ' +
'31-bit integer. Instead received: %s',
changedBits,
);
}
changedBits |= 0;
if (changedBits === 0) {
// No change. Bailout early if children are the same.
if (
oldProps.children === newProps.children &&
!hasLegacyContextChanged()
) {
workInProgress.stateNode = 0;
pushProvider(workInProgress);
return bailoutOnAlreadyFinishedWork(
current,
workInProgress,
renderExpirationTime,
);
}
} else {
propagateContextChange(
workInProgress,
context,
changedBits,
renderExpirationTime,
);
}
}
// The context value changed. Search for matching consumers and schedule
// them to update.
propagateContextChange(
workInProgress,
context,
changedBits,
renderExpirationTime,
);
}
}
workInProgress.stateNode = changedBits;
pushProvider(workInProgress);
pushProvider(workInProgress, changedBits);
const newChildren = newProps.children;
reconcileChildren(current, workInProgress, newChildren, renderExpirationTime);
@@ -1049,8 +996,7 @@ function beginWork(
);
break;
case ContextProvider:
workInProgress.stateNode = 0;
pushProvider(workInProgress);
pushProvider(workInProgress, 0);
break;
case Profiler:
if (enableProfilerTimer) {
+38 -3
View File
@@ -26,7 +26,9 @@ import {NoWork} from './ReactFiberExpirationTime';
import {ContextProvider} from 'shared/ReactTypeOfWork';
import invariant from 'shared/invariant';
import warning from 'shared/warning';
import MAX_SIGNED_31_BIT_INT from './maxSigned31BitInt';
const valueCursor: StackCursor<mixed> = createCursor(null);
const changedBitsCursor: StackCursor<number> = createCursor(0);
@@ -48,7 +50,7 @@ export function resetContextDependences(): void {
lastContextWithAllBitsObserved = null;
}
export function pushProvider(providerFiber: Fiber): void {
export function pushProvider(providerFiber: Fiber, changedBits: number): void {
const context: ReactContext<any> = providerFiber.type._context;
if (isPrimaryRenderer) {
@@ -56,7 +58,7 @@ export function pushProvider(providerFiber: Fiber): void {
push(valueCursor, context._currentValue, providerFiber);
context._currentValue = providerFiber.pendingProps.value;
context._changedBits = providerFiber.stateNode;
context._changedBits = changedBits;
if (__DEV__) {
warningWithoutStack(
context._currentRenderer === undefined ||
@@ -72,7 +74,7 @@ export function pushProvider(providerFiber: Fiber): void {
push(valueCursor, context._currentValue2, providerFiber);
context._currentValue2 = providerFiber.pendingProps.value;
context._changedBits2 = providerFiber.stateNode;
context._changedBits2 = changedBits;
if (__DEV__) {
warningWithoutStack(
context._currentRenderer2 === undefined ||
@@ -103,6 +105,39 @@ export function popProvider(providerFiber: Fiber): void {
}
}
export function calculateChangedBits<T>(
context: ReactContext<T>,
newValue: T,
oldValue: T,
) {
// Use Object.is to compare the new context value to the old value. Inlined
// Object.is polyfill.
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
if (
(oldValue === newValue &&
(oldValue !== 0 || 1 / oldValue === 1 / (newValue: any))) ||
(oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare
) {
// No change
return 0;
} else {
const changedBits =
typeof context._calculateChangedBits === 'function'
? context._calculateChangedBits(oldValue, newValue)
: MAX_SIGNED_31_BIT_INT;
if (__DEV__) {
warning(
(changedBits & MAX_SIGNED_31_BIT_INT) === changedBits,
'calculateChangedBits: Expected the return value to be a ' +
'31-bit integer. Instead received: %s',
changedBits,
);
}
return changedBits | 0;
}
}
export function propagateContextChange(
workInProgress: Fiber,
context: ReactContext<mixed>,
+1 -2
View File
@@ -50,13 +50,12 @@ export function createContext<T>(
const context: ReactContext<T> = {
$$typeof: REACT_CONTEXT_TYPE,
_calculateChangedBits: calculateChangedBits,
_defaultValue: defaultValue,
_currentValue: defaultValue,
// As a workaround to support multiple concurrent renderers, we categorize
// some renderers as primary and others as secondary. We only expect
// there to be two concurrent renderers at most: React Native (primary) and
// Fabric (secondary); React DOM (primary) and React ART (secondary).
// Secondary renderers store their context values on separate fields.
_currentValue: defaultValue,
_currentValue2: defaultValue,
_changedBits: 0,
_changedBits2: 0,
-1
View File
@@ -82,7 +82,6 @@ export type ReactContext<T> = {
unstable_read: () => T,
_calculateChangedBits: ((a: T, b: T) => number) | null,
_defaultValue: T,
_currentValue: T,
_currentValue2: T,