diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
index 397b739546dcc..3242fdd3e81f4 100644
--- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
+++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
@@ -736,17 +736,6 @@ describe('ReactDOMServerHooks', () => {
},
);
- itRenders('warns when bitmask is passed to useContext', async render => {
- const Context = React.createContext('Hi');
-
- function Foo() {
- return {useContext(Context, 1)};
- }
-
- const domNode = await render(, 1);
- expect(domNode.textContent).toBe('Hi');
- });
-
describe('useDebugValue', () => {
itRenders('is a noop', async render => {
function Counter(props) {
@@ -760,11 +749,11 @@ describe('ReactDOMServerHooks', () => {
});
describe('readContext', () => {
- function readContext(Context, observedBits) {
+ function readContext(Context) {
const dispatcher =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.ReactCurrentDispatcher.current;
- return dispatcher.readContext(Context, observedBits);
+ return dispatcher.readContext(Context);
}
itRenders(
diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.new.js b/packages/react-reconciler/src/ReactFiberBeginWork.new.js
index 345f668fc62e8..dd88f1beb8fd1 100644
--- a/packages/react-reconciler/src/ReactFiberBeginWork.new.js
+++ b/packages/react-reconciler/src/ReactFiberBeginWork.new.js
@@ -160,7 +160,6 @@ import {
checkIfContextChanged,
readContext,
prepareToReadContext,
- calculateChangedBits,
scheduleWorkOnParentPath,
} from './ReactFiberNewContext.new';
import {renderWithHooks, bailoutHooks} from './ReactFiberHooks.new';
@@ -221,7 +220,7 @@ import {
restoreSpawnedCachePool,
getOffscreenDeferredCachePool,
} from './ReactFiberCacheComponent.new';
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
+import is from 'shared/objectIs';
import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
@@ -796,12 +795,7 @@ function updateCacheComponent(
pushCacheProvider(workInProgress, nextCache);
if (nextCache !== prevState.cache) {
// This cache refreshed. Propagate a context change.
- propagateContextChange(
- workInProgress,
- CacheContext,
- MAX_SIGNED_31_BIT_INT,
- renderLanes,
- );
+ propagateContextChange(workInProgress, CacheContext, renderLanes);
}
}
}
@@ -1168,12 +1162,7 @@ function updateHostRoot(current, workInProgress, renderLanes) {
pushCacheProvider(workInProgress, nextCache);
if (nextCache !== prevState.cache) {
// The root cache refreshed.
- propagateContextChange(
- workInProgress,
- CacheContext,
- MAX_SIGNED_31_BIT_INT,
- renderLanes,
- );
+ propagateContextChange(workInProgress, CacheContext, renderLanes);
}
}
@@ -3007,8 +2996,7 @@ function updateContextProvider(
} else {
if (oldProps !== null) {
const oldValue = oldProps.value;
- const changedBits = calculateChangedBits(context, newValue, oldValue);
- if (changedBits === 0) {
+ if (is(oldValue, newValue)) {
// No change. Bailout early if children are the same.
if (
oldProps.children === newProps.children &&
@@ -3023,12 +3011,7 @@ function updateContextProvider(
} else {
// The context value changed. Search for matching consumers and schedule
// them to update.
- propagateContextChange(
- workInProgress,
- context,
- changedBits,
- renderLanes,
- );
+ propagateContextChange(workInProgress, context, renderLanes);
}
}
}
@@ -3086,7 +3069,7 @@ function updateContextConsumer(
}
prepareToReadContext(workInProgress, renderLanes);
- const newValue = readContext(context, newProps.unstable_observedBits);
+ const newValue = readContext(context);
let newChildren;
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
diff --git a/packages/react-reconciler/src/ReactFiberBeginWork.old.js b/packages/react-reconciler/src/ReactFiberBeginWork.old.js
index 72b4e33431b00..1dd3ff43ffac1 100644
--- a/packages/react-reconciler/src/ReactFiberBeginWork.old.js
+++ b/packages/react-reconciler/src/ReactFiberBeginWork.old.js
@@ -160,7 +160,6 @@ import {
checkIfContextChanged,
readContext,
prepareToReadContext,
- calculateChangedBits,
scheduleWorkOnParentPath,
} from './ReactFiberNewContext.old';
import {renderWithHooks, bailoutHooks} from './ReactFiberHooks.old';
@@ -221,7 +220,7 @@ import {
restoreSpawnedCachePool,
getOffscreenDeferredCachePool,
} from './ReactFiberCacheComponent.old';
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
+import is from 'shared/objectIs';
import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
@@ -796,12 +795,7 @@ function updateCacheComponent(
pushCacheProvider(workInProgress, nextCache);
if (nextCache !== prevState.cache) {
// This cache refreshed. Propagate a context change.
- propagateContextChange(
- workInProgress,
- CacheContext,
- MAX_SIGNED_31_BIT_INT,
- renderLanes,
- );
+ propagateContextChange(workInProgress, CacheContext, renderLanes);
}
}
}
@@ -1168,12 +1162,7 @@ function updateHostRoot(current, workInProgress, renderLanes) {
pushCacheProvider(workInProgress, nextCache);
if (nextCache !== prevState.cache) {
// The root cache refreshed.
- propagateContextChange(
- workInProgress,
- CacheContext,
- MAX_SIGNED_31_BIT_INT,
- renderLanes,
- );
+ propagateContextChange(workInProgress, CacheContext, renderLanes);
}
}
@@ -3007,8 +2996,7 @@ function updateContextProvider(
} else {
if (oldProps !== null) {
const oldValue = oldProps.value;
- const changedBits = calculateChangedBits(context, newValue, oldValue);
- if (changedBits === 0) {
+ if (is(oldValue, newValue)) {
// No change. Bailout early if children are the same.
if (
oldProps.children === newProps.children &&
@@ -3023,12 +3011,7 @@ function updateContextProvider(
} else {
// The context value changed. Search for matching consumers and schedule
// them to update.
- propagateContextChange(
- workInProgress,
- context,
- changedBits,
- renderLanes,
- );
+ propagateContextChange(workInProgress, context, renderLanes);
}
}
}
@@ -3086,7 +3069,7 @@ function updateContextConsumer(
}
prepareToReadContext(workInProgress, renderLanes);
- const newValue = readContext(context, newProps.unstable_observedBits);
+ const newValue = readContext(context);
let newChildren;
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
diff --git a/packages/react-reconciler/src/ReactFiberCacheComponent.new.js b/packages/react-reconciler/src/ReactFiberCacheComponent.new.js
index b5ae3ccc611a8..042a8b2efc098 100644
--- a/packages/react-reconciler/src/ReactFiberCacheComponent.new.js
+++ b/packages/react-reconciler/src/ReactFiberCacheComponent.new.js
@@ -37,7 +37,6 @@ export const CacheContext: ReactContext = enableCache
// We don't use Consumer/Provider for Cache components. So we'll cheat.
Consumer: (null: any),
Provider: (null: any),
- _calculateChangedBits: null,
// We'll initialize these at the root.
_currentValue: (null: any),
_currentValue2: (null: any),
diff --git a/packages/react-reconciler/src/ReactFiberCacheComponent.old.js b/packages/react-reconciler/src/ReactFiberCacheComponent.old.js
index 8882f7dbd2d48..2bc64254d3092 100644
--- a/packages/react-reconciler/src/ReactFiberCacheComponent.old.js
+++ b/packages/react-reconciler/src/ReactFiberCacheComponent.old.js
@@ -37,7 +37,6 @@ export const CacheContext: ReactContext = enableCache
// We don't use Consumer/Provider for Cache components. So we'll cheat.
Consumer: (null: any),
Provider: (null: any),
- _calculateChangedBits: null,
// We'll initialize these at the root.
_currentValue: (null: any),
_currentValue2: (null: any),
diff --git a/packages/react-reconciler/src/ReactFiberHooks.new.js b/packages/react-reconciler/src/ReactFiberHooks.new.js
index e7e5c3128beac..3c1c6c43081fc 100644
--- a/packages/react-reconciler/src/ReactFiberHooks.new.js
+++ b/packages/react-reconciler/src/ReactFiberHooks.new.js
@@ -2238,11 +2238,8 @@ if (__DEV__) {
};
HooksDispatcherOnMountInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
- return readContext(context, observedBits);
+ readContext(context: ReactContext): T {
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
@@ -2250,13 +2247,10 @@ if (__DEV__) {
checkDepsAreArrayDev(deps);
return mountCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
mountHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2373,24 +2367,18 @@ if (__DEV__) {
}
HooksDispatcherOnMountWithHookTypesInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
- return readContext(context, observedBits);
+ readContext(context: ReactContext): T {
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
updateHookTypesDev();
return mountCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2503,24 +2491,18 @@ if (__DEV__) {
}
HooksDispatcherOnUpdateInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
- return readContext(context, observedBits);
+ readContext(context: ReactContext): T {
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
updateHookTypesDev();
return updateCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2633,11 +2615,8 @@ if (__DEV__) {
}
HooksDispatcherOnRerenderInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
- return readContext(context, observedBits);
+ readContext(context: ReactContext): T {
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
@@ -2645,13 +2624,10 @@ if (__DEV__) {
updateHookTypesDev();
return updateCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2764,12 +2740,9 @@ if (__DEV__) {
}
InvalidNestedHooksDispatcherOnMountInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ readContext(context: ReactContext): T {
warnInvalidContextAccess();
- return readContext(context, observedBits);
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
@@ -2777,14 +2750,11 @@ if (__DEV__) {
mountHookTypesDev();
return mountCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
mountHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2909,12 +2879,9 @@ if (__DEV__) {
}
InvalidNestedHooksDispatcherOnUpdateInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ readContext(context: ReactContext): T {
warnInvalidContextAccess();
- return readContext(context, observedBits);
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
@@ -2922,14 +2889,11 @@ if (__DEV__) {
updateHookTypesDev();
return updateCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -3054,12 +3018,9 @@ if (__DEV__) {
}
InvalidNestedHooksDispatcherOnRerenderInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ readContext(context: ReactContext): T {
warnInvalidContextAccess();
- return readContext(context, observedBits);
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
@@ -3068,14 +3029,11 @@ if (__DEV__) {
updateHookTypesDev();
return updateCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
diff --git a/packages/react-reconciler/src/ReactFiberHooks.old.js b/packages/react-reconciler/src/ReactFiberHooks.old.js
index 55dca75656c35..2a0f70e1913b6 100644
--- a/packages/react-reconciler/src/ReactFiberHooks.old.js
+++ b/packages/react-reconciler/src/ReactFiberHooks.old.js
@@ -2238,11 +2238,8 @@ if (__DEV__) {
};
HooksDispatcherOnMountInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
- return readContext(context, observedBits);
+ readContext(context: ReactContext): T {
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
@@ -2250,13 +2247,10 @@ if (__DEV__) {
checkDepsAreArrayDev(deps);
return mountCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
mountHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2373,24 +2367,18 @@ if (__DEV__) {
}
HooksDispatcherOnMountWithHookTypesInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
- return readContext(context, observedBits);
+ readContext(context: ReactContext): T {
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
updateHookTypesDev();
return mountCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2503,24 +2491,18 @@ if (__DEV__) {
}
HooksDispatcherOnUpdateInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
- return readContext(context, observedBits);
+ readContext(context: ReactContext): T {
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
updateHookTypesDev();
return updateCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2633,11 +2615,8 @@ if (__DEV__) {
}
HooksDispatcherOnRerenderInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
- return readContext(context, observedBits);
+ readContext(context: ReactContext): T {
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
@@ -2645,13 +2624,10 @@ if (__DEV__) {
updateHookTypesDev();
return updateCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2764,12 +2740,9 @@ if (__DEV__) {
}
InvalidNestedHooksDispatcherOnMountInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ readContext(context: ReactContext): T {
warnInvalidContextAccess();
- return readContext(context, observedBits);
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
@@ -2777,14 +2750,11 @@ if (__DEV__) {
mountHookTypesDev();
return mountCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
mountHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -2909,12 +2879,9 @@ if (__DEV__) {
}
InvalidNestedHooksDispatcherOnUpdateInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ readContext(context: ReactContext): T {
warnInvalidContextAccess();
- return readContext(context, observedBits);
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
currentHookNameInDev = 'useCallback';
@@ -2922,14 +2889,11 @@ if (__DEV__) {
updateHookTypesDev();
return updateCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
@@ -3054,12 +3018,9 @@ if (__DEV__) {
}
InvalidNestedHooksDispatcherOnRerenderInDEV = {
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ readContext(context: ReactContext): T {
warnInvalidContextAccess();
- return readContext(context, observedBits);
+ return readContext(context);
},
useCallback(callback: T, deps: Array | void | null): T {
@@ -3068,14 +3029,11 @@ if (__DEV__) {
updateHookTypesDev();
return updateCallback(callback, deps);
},
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T {
+ useContext(context: ReactContext): T {
currentHookNameInDev = 'useContext';
warnInvalidHookAccess();
updateHookTypesDev();
- return readContext(context, observedBits);
+ return readContext(context);
},
useEffect(
create: () => (() => void) | void,
diff --git a/packages/react-reconciler/src/ReactFiberNewContext.new.js b/packages/react-reconciler/src/ReactFiberNewContext.new.js
index 29a1eeef8cdd9..9d2484a783971 100644
--- a/packages/react-reconciler/src/ReactFiberNewContext.new.js
+++ b/packages/react-reconciler/src/ReactFiberNewContext.new.js
@@ -19,7 +19,6 @@ import type {SharedQueue} from './ReactUpdateQueue.new';
import {isPrimaryRenderer} from './ReactFiberHostConfig';
import {createCursor, push, pop} from './ReactFiberStack.new';
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
import {
ContextProvider,
ClassComponent,
@@ -58,7 +57,7 @@ if (__DEV__) {
let currentlyRenderingFiber: Fiber | null = null;
let lastContextDependency: ContextDependency | null = null;
-let lastContextWithAllBitsObserved: ReactContext | null = null;
+let lastFullyObservedContext: ReactContext | null = null;
let isDisallowedContextReadInDEV: boolean = false;
@@ -67,7 +66,7 @@ export function resetContextDependencies(): void {
// cannot be called outside the render phase.
currentlyRenderingFiber = null;
lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
+ lastFullyObservedContext = null;
if (__DEV__) {
isDisallowedContextReadInDEV = false;
}
@@ -140,33 +139,6 @@ export function popProvider(
}
}
-export function calculateChangedBits(
- context: ReactContext,
- newValue: T,
- oldValue: T,
-) {
- if (is(oldValue, newValue)) {
- // No change
- return 0;
- } else {
- const changedBits =
- typeof context._calculateChangedBits === 'function'
- ? context._calculateChangedBits(oldValue, newValue)
- : MAX_SIGNED_31_BIT_INT;
-
- if (__DEV__) {
- if ((changedBits & MAX_SIGNED_31_BIT_INT) !== changedBits) {
- console.error(
- 'calculateChangedBits: Expected the return value to be a ' +
- '31-bit integer. Instead received: %s',
- changedBits,
- );
- }
- }
- return changedBits | 0;
- }
-}
-
export function scheduleWorkOnParentPath(
parent: Fiber | null,
renderLanes: Lanes,
@@ -197,7 +169,6 @@ export function scheduleWorkOnParentPath(
export function propagateContextChange(
workInProgress: Fiber,
context: ReactContext,
- changedBits: number,
renderLanes: Lanes,
): void {
if (enableLazyContextPropagation) {
@@ -207,24 +178,18 @@ export function propagateContextChange(
const forcePropagateEntireTree = true;
propagateContextChanges(
workInProgress,
- [context, changedBits],
+ [context],
renderLanes,
forcePropagateEntireTree,
);
} else {
- propagateContextChange_eager(
- workInProgress,
- context,
- changedBits,
- renderLanes,
- );
+ propagateContextChange_eager(workInProgress, context, renderLanes);
}
}
function propagateContextChange_eager(
workInProgress: Fiber,
context: ReactContext,
- changedBits: number,
renderLanes: Lanes,
): void {
// Only used by eager implemenation
@@ -247,10 +212,7 @@ function propagateContextChange_eager(
let dependency = list.firstContext;
while (dependency !== null) {
// Check if the context matches.
- if (
- dependency.context === context &&
- (dependency.observedBits & changedBits) !== 0
- ) {
+ if (dependency.context === context) {
// Match! Schedule an update on this fiber.
if (fiber.tag === ClassComponent) {
// Schedule a force update on the work-in-progress.
@@ -382,15 +344,11 @@ function propagateContextChanges(
// Assigning these to constants to help Flow
const dependency = dep;
const consumer = fiber;
- findContext: for (let i = 0; i < contexts.length; i += 2) {
+ findContext: for (let i = 0; i < contexts.length; i++) {
const context: ReactContext = contexts[i];
- const changedBits: number = contexts[i + 1];
// Check if the context matches.
// TODO: Compare selected values to bail out early.
- if (
- dependency.context === context &&
- (dependency.observedBits & changedBits) !== 0
- ) {
+ if (dependency.context === context) {
// Match! Schedule an update on this fiber.
// In the lazy implemenation, don't mark a dirty flag on the
@@ -549,12 +507,11 @@ function propagateParentContextChanges(
const oldValue = oldProps.value;
- const changedBits = calculateChangedBits(context, newValue, oldValue);
- if (changedBits !== 0) {
+ if (!is(newValue, oldValue)) {
if (contexts !== null) {
- contexts.push(context, changedBits);
+ contexts.push(context);
} else {
- contexts = [context, changedBits];
+ contexts = [context];
}
}
}
@@ -625,7 +582,7 @@ export function prepareToReadContext(
): void {
currentlyRenderingFiber = workInProgress;
lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
+ lastFullyObservedContext = null;
const dependencies = workInProgress.dependencies;
if (dependencies !== null) {
@@ -646,10 +603,7 @@ export function prepareToReadContext(
}
}
-export function readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
-): T {
+export function readContext(context: ReactContext): T {
if (__DEV__) {
// This warning would fire if you read context inside a Hook like useMemo.
// Unlike the class check below, it's not enforced in production for perf.
@@ -667,26 +621,11 @@ export function readContext(
? context._currentValue
: context._currentValue2;
- if (lastContextWithAllBitsObserved === context) {
+ if (lastFullyObservedContext === context) {
// Nothing to do. We already observe everything in this context.
- } else if (observedBits === false || observedBits === 0) {
- // Do not observe any updates.
} else {
- let resolvedObservedBits; // Avoid deopting on observable arguments or heterogeneous types.
- if (
- typeof observedBits !== 'number' ||
- observedBits === MAX_SIGNED_31_BIT_INT
- ) {
- // Observe all updates.
- lastContextWithAllBitsObserved = ((context: any): ReactContext);
- resolvedObservedBits = MAX_SIGNED_31_BIT_INT;
- } else {
- resolvedObservedBits = observedBits;
- }
-
const contextItem = {
context: ((context: any): ReactContext),
- observedBits: resolvedObservedBits,
memoizedValue: value,
next: null,
};
diff --git a/packages/react-reconciler/src/ReactFiberNewContext.old.js b/packages/react-reconciler/src/ReactFiberNewContext.old.js
index 0e6ed587b8ddb..c2a1600650119 100644
--- a/packages/react-reconciler/src/ReactFiberNewContext.old.js
+++ b/packages/react-reconciler/src/ReactFiberNewContext.old.js
@@ -19,7 +19,6 @@ import type {SharedQueue} from './ReactUpdateQueue.old';
import {isPrimaryRenderer} from './ReactFiberHostConfig';
import {createCursor, push, pop} from './ReactFiberStack.old';
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
import {
ContextProvider,
ClassComponent,
@@ -58,7 +57,7 @@ if (__DEV__) {
let currentlyRenderingFiber: Fiber | null = null;
let lastContextDependency: ContextDependency | null = null;
-let lastContextWithAllBitsObserved: ReactContext | null = null;
+let lastFullyObservedContext: ReactContext | null = null;
let isDisallowedContextReadInDEV: boolean = false;
@@ -67,7 +66,7 @@ export function resetContextDependencies(): void {
// cannot be called outside the render phase.
currentlyRenderingFiber = null;
lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
+ lastFullyObservedContext = null;
if (__DEV__) {
isDisallowedContextReadInDEV = false;
}
@@ -140,33 +139,6 @@ export function popProvider(
}
}
-export function calculateChangedBits(
- context: ReactContext,
- newValue: T,
- oldValue: T,
-) {
- if (is(oldValue, newValue)) {
- // No change
- return 0;
- } else {
- const changedBits =
- typeof context._calculateChangedBits === 'function'
- ? context._calculateChangedBits(oldValue, newValue)
- : MAX_SIGNED_31_BIT_INT;
-
- if (__DEV__) {
- if ((changedBits & MAX_SIGNED_31_BIT_INT) !== changedBits) {
- console.error(
- 'calculateChangedBits: Expected the return value to be a ' +
- '31-bit integer. Instead received: %s',
- changedBits,
- );
- }
- }
- return changedBits | 0;
- }
-}
-
export function scheduleWorkOnParentPath(
parent: Fiber | null,
renderLanes: Lanes,
@@ -197,7 +169,6 @@ export function scheduleWorkOnParentPath(
export function propagateContextChange(
workInProgress: Fiber,
context: ReactContext,
- changedBits: number,
renderLanes: Lanes,
): void {
if (enableLazyContextPropagation) {
@@ -207,24 +178,18 @@ export function propagateContextChange(
const forcePropagateEntireTree = true;
propagateContextChanges(
workInProgress,
- [context, changedBits],
+ [context],
renderLanes,
forcePropagateEntireTree,
);
} else {
- propagateContextChange_eager(
- workInProgress,
- context,
- changedBits,
- renderLanes,
- );
+ propagateContextChange_eager(workInProgress, context, renderLanes);
}
}
function propagateContextChange_eager(
workInProgress: Fiber,
context: ReactContext,
- changedBits: number,
renderLanes: Lanes,
): void {
// Only used by eager implemenation
@@ -247,10 +212,7 @@ function propagateContextChange_eager(
let dependency = list.firstContext;
while (dependency !== null) {
// Check if the context matches.
- if (
- dependency.context === context &&
- (dependency.observedBits & changedBits) !== 0
- ) {
+ if (dependency.context === context) {
// Match! Schedule an update on this fiber.
if (fiber.tag === ClassComponent) {
// Schedule a force update on the work-in-progress.
@@ -382,15 +344,11 @@ function propagateContextChanges(
// Assigning these to constants to help Flow
const dependency = dep;
const consumer = fiber;
- findContext: for (let i = 0; i < contexts.length; i += 2) {
+ findContext: for (let i = 0; i < contexts.length; i++) {
const context: ReactContext = contexts[i];
- const changedBits: number = contexts[i + 1];
// Check if the context matches.
// TODO: Compare selected values to bail out early.
- if (
- dependency.context === context &&
- (dependency.observedBits & changedBits) !== 0
- ) {
+ if (dependency.context === context) {
// Match! Schedule an update on this fiber.
// In the lazy implemenation, don't mark a dirty flag on the
@@ -549,12 +507,11 @@ function propagateParentContextChanges(
const oldValue = oldProps.value;
- const changedBits = calculateChangedBits(context, newValue, oldValue);
- if (changedBits !== 0) {
+ if (!is(newValue, oldValue)) {
if (contexts !== null) {
- contexts.push(context, changedBits);
+ contexts.push(context);
} else {
- contexts = [context, changedBits];
+ contexts = [context];
}
}
}
@@ -625,7 +582,7 @@ export function prepareToReadContext(
): void {
currentlyRenderingFiber = workInProgress;
lastContextDependency = null;
- lastContextWithAllBitsObserved = null;
+ lastFullyObservedContext = null;
const dependencies = workInProgress.dependencies;
if (dependencies !== null) {
@@ -646,10 +603,7 @@ export function prepareToReadContext(
}
}
-export function readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
-): T {
+export function readContext(context: ReactContext): T {
if (__DEV__) {
// This warning would fire if you read context inside a Hook like useMemo.
// Unlike the class check below, it's not enforced in production for perf.
@@ -667,26 +621,11 @@ export function readContext(
? context._currentValue
: context._currentValue2;
- if (lastContextWithAllBitsObserved === context) {
+ if (lastFullyObservedContext === context) {
// Nothing to do. We already observe everything in this context.
- } else if (observedBits === false || observedBits === 0) {
- // Do not observe any updates.
} else {
- let resolvedObservedBits; // Avoid deopting on observable arguments or heterogeneous types.
- if (
- typeof observedBits !== 'number' ||
- observedBits === MAX_SIGNED_31_BIT_INT
- ) {
- // Observe all updates.
- lastContextWithAllBitsObserved = ((context: any): ReactContext);
- resolvedObservedBits = MAX_SIGNED_31_BIT_INT;
- } else {
- resolvedObservedBits = observedBits;
- }
-
const contextItem = {
context: ((context: any): ReactContext),
- observedBits: resolvedObservedBits,
memoizedValue: value,
next: null,
};
diff --git a/packages/react-reconciler/src/ReactInternalTypes.js b/packages/react-reconciler/src/ReactInternalTypes.js
index b1764bed5ac34..e5fd43e6f416e 100644
--- a/packages/react-reconciler/src/ReactInternalTypes.js
+++ b/packages/react-reconciler/src/ReactInternalTypes.js
@@ -49,7 +49,6 @@ export type ReactPriorityLevel = 99 | 98 | 97 | 96 | 95 | 90;
export type ContextDependency = {
context: ReactContext,
- observedBits: number,
next: ContextDependency | null,
memoizedValue: T,
...
@@ -281,20 +280,14 @@ type Dispatch = A => void;
export type Dispatcher = {|
getCacheForType?: (resourceType: () => T) => T,
- readContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T,
+ readContext(context: ReactContext): T,
useState(initialState: (() => S) | S): [S, Dispatch>],
useReducer(
reducer: (S, A) => S,
initialArg: I,
init?: (I) => S,
): [S, Dispatch],
- useContext(
- context: ReactContext,
- observedBits: void | number | boolean,
- ): T,
+ useContext(context: ReactContext): T,
useRef(initialValue: T): {|current: T|},
useEffect(
create: () => (() => void) | void,
diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js
index 43c1e0033c2f3..4f64972715ac4 100644
--- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.js
+++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.js
@@ -35,11 +35,11 @@ describe('ReactNewContext', () => {
return {type: 'span', children: [], prop, hidden: false};
}
- function readContext(Context, observedBits) {
+ function readContext(Context) {
const dispatcher =
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
.ReactCurrentDispatcher.current;
- return dispatcher.readContext(Context, observedBits);
+ return dispatcher.readContext(Context);
}
// Note: This is based on a similar component we use in www. We can delete
@@ -62,48 +62,21 @@ describe('ReactNewContext', () => {
'useContext inside function component',
Context =>
function Consumer(props) {
- const observedBits = props.unstable_observedBits;
- let contextValue;
- expect(() => {
- contextValue = useContext(Context, observedBits);
- }).toErrorDev(
- observedBits !== undefined
- ? 'useContext() second argument is reserved for future use in React. ' +
- `Passing it is not supported. You passed: ${observedBits}.`
- : [],
- );
+ const contextValue = useContext(Context);
const render = props.children;
return render(contextValue);
},
);
sharedContextTests('useContext inside forwardRef component', Context =>
React.forwardRef(function Consumer(props, ref) {
- const observedBits = props.unstable_observedBits;
- let contextValue;
- expect(() => {
- contextValue = useContext(Context, observedBits);
- }).toErrorDev(
- observedBits !== undefined
- ? 'useContext() second argument is reserved for future use in React. ' +
- `Passing it is not supported. You passed: ${observedBits}.`
- : [],
- );
+ const contextValue = useContext(Context);
const render = props.children;
return render(contextValue);
}),
);
sharedContextTests('useContext inside memoized function component', Context =>
React.memo(function Consumer(props) {
- const observedBits = props.unstable_observedBits;
- let contextValue;
- expect(() => {
- contextValue = useContext(Context, observedBits);
- }).toErrorDev(
- observedBits !== undefined
- ? 'useContext() second argument is reserved for future use in React. ' +
- `Passing it is not supported. You passed: ${observedBits}.`
- : [],
- );
+ const contextValue = useContext(Context);
const render = props.children;
return render(contextValue);
}),
@@ -113,8 +86,7 @@ describe('ReactNewContext', () => {
Context =>
class Consumer extends React.Component {
render() {
- const observedBits = this.props.unstable_observedBits;
- const contextValue = readContext(Context, observedBits);
+ const contextValue = readContext(Context);
const render = this.props.children;
return render(contextValue);
}
@@ -125,8 +97,7 @@ describe('ReactNewContext', () => {
Context =>
class Consumer extends React.PureComponent {
render() {
- const observedBits = this.props.unstable_observedBits;
- const contextValue = readContext(Context, observedBits);
+ const contextValue = readContext(Context);
const render = this.props.children;
return render(contextValue);
}
@@ -590,227 +561,6 @@ describe('ReactNewContext', () => {
]);
});
- it('can skip consumers with bitmask', () => {
- const Context = React.createContext({foo: 0, bar: 0}, (a, b) => {
- let result = 0;
- if (a.foo !== b.foo) {
- result |= 0b01;
- }
- if (a.bar !== b.bar) {
- result |= 0b10;
- }
- return result;
- });
- const Consumer = getConsumer(Context);
-
- function Provider(props) {
- return (
-
- {props.children}
-
- );
- }
-
- function Foo() {
- return (
-
- {value => {
- Scheduler.unstable_yieldValue('Foo');
- return ;
- }}
-
- );
- }
-
- function Bar() {
- return (
-
- {value => {
- Scheduler.unstable_yieldValue('Bar');
- return ;
- }}
-
- );
- }
-
- class Indirection extends React.Component {
- shouldComponentUpdate() {
- return false;
- }
- render() {
- return this.props.children;
- }
- }
-
- function App(props) {
- return (
-
-
-
-
-
-
-
-
-
-
- );
- }
-
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar']);
- expect(ReactNoop.getChildren()).toEqual([
- span('Foo: 1'),
- span('Bar: 1'),
- ]);
-
- // Update only foo
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield(['Foo']);
- expect(ReactNoop.getChildren()).toEqual([
- span('Foo: 2'),
- span('Bar: 1'),
- ]);
-
- // Update only bar
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield(['Bar']);
- expect(ReactNoop.getChildren()).toEqual([
- span('Foo: 2'),
- span('Bar: 2'),
- ]);
-
- // Update both
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar']);
- expect(ReactNoop.getChildren()).toEqual([
- span('Foo: 3'),
- span('Bar: 3'),
- ]);
- });
-
- // @gate !enableLazyContextPropagation
- it('can skip parents with bitmask bailout while updating their children', () => {
- const Context = React.createContext({foo: 0, bar: 0}, (a, b) => {
- let result = 0;
- if (a.foo !== b.foo) {
- result |= 0b01;
- }
- if (a.bar !== b.bar) {
- result |= 0b10;
- }
- return result;
- });
- const Consumer = getConsumer(Context);
-
- function Provider(props) {
- return (
-
- {props.children}
-
- );
- }
-
- function Foo(props) {
- return (
-
- {value => {
- Scheduler.unstable_yieldValue('Foo');
- return (
- <>
-
- {props.children && props.children()}
- >
- );
- }}
-
- );
- }
-
- function Bar(props) {
- return (
-
- {value => {
- Scheduler.unstable_yieldValue('Bar');
- return (
- <>
-
- {props.children && props.children()}
- >
- );
- }}
-
- );
- }
-
- class Indirection extends React.Component {
- shouldComponentUpdate() {
- return false;
- }
- render() {
- return this.props.children;
- }
- }
-
- function App(props) {
- return (
-
-
-
- {/* Use a render prop so we don't test constant elements. */}
- {() => (
-
-
- {() => (
-
-
-
- )}
-
-
- )}
-
-
-
- );
- }
-
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar', 'Foo']);
- expect(ReactNoop.getChildren()).toEqual([
- span('Foo: 1'),
- span('Bar: 1'),
- span('Foo: 1'),
- ]);
-
- // Update only foo
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield(['Foo', 'Foo']);
- expect(ReactNoop.getChildren()).toEqual([
- span('Foo: 2'),
- span('Bar: 1'),
- span('Foo: 2'),
- ]);
-
- // Update only bar
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield(['Bar']);
- expect(ReactNoop.getChildren()).toEqual([
- span('Foo: 2'),
- span('Bar: 2'),
- span('Foo: 2'),
- ]);
-
- // Update both
- ReactNoop.render();
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar', 'Foo']);
- expect(ReactNoop.getChildren()).toEqual([
- span('Foo: 3'),
- span('Bar: 3'),
- span('Foo: 3'),
- ]);
- });
-
it("does not re-render if there's an update in a child", () => {
const Context = React.createContext(0);
const Consumer = getConsumer(Context);
@@ -1063,30 +813,6 @@ describe('ReactNewContext', () => {
}
describe('Context.Provider', () => {
- it('warns if calculateChangedBits returns larger than a 31-bit integer', () => {
- const Context = React.createContext(
- 0,
- (a, b) => Math.pow(2, 32) - 1, // Return 32 bit int
- );
-
- function App(props) {
- return ;
- }
-
- ReactNoop.render();
- expect(Scheduler).toFlushWithoutYielding();
-
- // Update
- ReactNoop.render();
-
- if (gate(flags => !flags.enableLazyContextPropagation)) {
- expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
- 'calculateChangedBits: Expected the return value to be a 31-bit ' +
- 'integer. Instead received: 4294967295',
- );
- }
- });
-
it('warns if no value prop provided', () => {
const Context = React.createContext();
@@ -1355,6 +1081,9 @@ describe('ReactNewContext', () => {
});
describe('readContext', () => {
+ // Unstable changedBits API was removed. Port this test to context selectors
+ // once that exists.
+ // @gate FIXME
it('can read the same context multiple times in the same function', () => {
const Context = React.createContext({foo: 0, bar: 0, baz: 0}, (a, b) => {
let result = 0;
@@ -1517,22 +1246,6 @@ describe('ReactNewContext', () => {
});
describe('useContext', () => {
- it('warns on array.map(useContext)', () => {
- const Context = React.createContext(0);
- function Foo() {
- return [Context].map(useContext);
- }
- ReactNoop.render();
- expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
- 'useContext() second argument is reserved for future ' +
- 'use in React. Passing it is not supported. ' +
- 'You passed: 0.\n\n' +
- 'Did you call array.map(useContext)? ' +
- 'Calling Hooks inside a loop is not supported. ' +
- 'Learn more at https://reactjs.org/link/rules-of-hooks',
- );
- });
-
it('throws when used in a class component', () => {
const Context = React.createContext(0);
class Foo extends React.Component {
diff --git a/packages/react/src/ReactContext.js b/packages/react/src/ReactContext.js
index a3c4243dd0116..41065c13ef067 100644
--- a/packages/react/src/ReactContext.js
+++ b/packages/react/src/ReactContext.js
@@ -11,30 +11,12 @@ import {REACT_PROVIDER_TYPE, REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';
import type {ReactContext} from 'shared/ReactTypes';
-export function createContext(
- defaultValue: T,
- calculateChangedBits: ?(a: T, b: T) => number,
-): ReactContext {
- if (calculateChangedBits === undefined) {
- calculateChangedBits = null;
- } else {
- if (__DEV__) {
- if (
- calculateChangedBits !== null &&
- typeof calculateChangedBits !== 'function'
- ) {
- console.error(
- 'createContext: Expected the optional second argument to be a ' +
- 'function. Instead received: %s',
- calculateChangedBits,
- );
- }
- }
- }
+export function createContext(defaultValue: T): ReactContext {
+ // TODO: Second argument used to be an optional `calculateChangedBits`
+ // function. Warn to reserve for future use?
const context: ReactContext = {
$$typeof: REACT_CONTEXT_TYPE,
- _calculateChangedBits: calculateChangedBits,
// 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
@@ -66,7 +48,6 @@ export function createContext(
const Consumer = {
$$typeof: REACT_CONTEXT_TYPE,
_context: context,
- _calculateChangedBits: context._calculateChangedBits,
};
// $FlowFixMe: Flow complains about not setting a value, which is intentional here
Object.defineProperties(Consumer, {
diff --git a/packages/react/src/ReactHooks.js b/packages/react/src/ReactHooks.js
index d397d8f789f0a..18920be2c8df4 100644
--- a/packages/react/src/ReactHooks.js
+++ b/packages/react/src/ReactHooks.js
@@ -47,26 +47,9 @@ export function getCacheForType(resourceType: () => T): T {
return dispatcher.getCacheForType(resourceType);
}
-export function useContext(
- Context: ReactContext,
- unstable_observedBits: number | boolean | void,
-): T {
+export function useContext(Context: ReactContext): T {
const dispatcher = resolveDispatcher();
if (__DEV__) {
- if (unstable_observedBits !== undefined) {
- console.error(
- 'useContext() second argument is reserved for future ' +
- 'use in React. Passing it is not supported. ' +
- 'You passed: %s.%s',
- unstable_observedBits,
- typeof unstable_observedBits === 'number' && Array.isArray(arguments[2])
- ? '\n\nDid you call array.map(useContext)? ' +
- 'Calling Hooks inside a loop is not supported. ' +
- 'Learn more at https://reactjs.org/link/rules-of-hooks'
- : '',
- );
- }
-
// TODO: add a more generic warning for invalid values.
if ((Context: any)._context !== undefined) {
const realContext = (Context: any)._context;
@@ -85,7 +68,7 @@ export function useContext(
}
}
}
- return dispatcher.useContext(Context, unstable_observedBits);
+ return dispatcher.useContext(Context);
}
export function useState(
diff --git a/packages/shared/ReactTypes.js b/packages/shared/ReactTypes.js
index dc31b998ea31c..55061fe8b9b82 100644
--- a/packages/shared/ReactTypes.js
+++ b/packages/shared/ReactTypes.js
@@ -59,7 +59,6 @@ export type ReactContext = {
$$typeof: Symbol | number,
Consumer: ReactContext,
Provider: ReactProviderType,
- _calculateChangedBits: ((a: T, b: T) => number) | null,
_currentValue: T,
_currentValue2: T,
_threadCount: number,