mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
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:
+15
-69
@@ -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
@@ -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>,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -82,7 +82,6 @@ export type ReactContext<T> = {
|
||||
unstable_read: () => T,
|
||||
|
||||
_calculateChangedBits: ((a: T, b: T) => number) | null,
|
||||
_defaultValue: T,
|
||||
|
||||
_currentValue: T,
|
||||
_currentValue2: T,
|
||||
|
||||
Reference in New Issue
Block a user