Remove unstable_changedBits (#20953)
We added this unstable feature a few years ago, as a way to opt out of context updates, but it didn't prove useful in practice. We have other proposals for how to address the same problem, like context selectors. Since it was prefixed with `unstable_`, we should be able to remove it without consequence. The hook API already warned if you used it. Even if someone is using it somewhere, it's meant to be an optimization only, so if they are using the API properly, it should not have any semantic impact.
Andrew Clark committed
Mar 19, 2021 at 17:36 UTC
6d3ecb70dceb225af0cd990b46d6c44b852c1d82
19 files changed
+123
-720
packages/react-cache/src/ReactCacheOld.js
+2
-2
@@ -46,7 +46,7 @@ const ReactCurrentDispatcher =
46
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
47
.ReactCurrentDispatcher;
48
49
-function readContext(Context, observedBits) {
49
+function readContext(Context) {
50
const dispatcher = ReactCurrentDispatcher.current;
51
if (dispatcher === null) {
52
throw new Error(
@@ -55,7 +55,7 @@ function readContext(Context, observedBits) {
55
'lifecycle methods.',
56
);
57
}
58
- return dispatcher.readContext(Context, observedBits);
58
+ return dispatcher.readContext(Context);
59
}
60
61
function identityHashFn(input) {
packages/react-debug-tools/src/ReactDebugHooks.js
+2
-8
@@ -109,18 +109,12 @@ function getCacheForType<T>(resourceType: () => T): T {
109
invariant(false, 'Not implemented.');
110
}
111
112
-function readContext<T>(
113
- context: ReactContext<T>,
114
- observedBits: void | number | boolean,
115
-): T {
112
+function readContext<T>(context: ReactContext<T>): T {
113
// For now we don't expose readContext usage in the hooks debugging info.
114
return context._currentValue;
115
}
116
120
-function useContext<T>(
121
- context: ReactContext<T>,
122
- observedBits: void | number | boolean,
123
-): T {
117
+function useContext<T>(context: ReactContext<T>): T {
118
hookLog.push({
119
primitive: 'Context',
120
stackError: new Error(),
packages/react-devtools-shared/src/devtools/cache.js
+2
-2
@@ -61,7 +61,7 @@ const Rejected = 2;
61
const ReactCurrentDispatcher = (React: any)
62
.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher;
63
64
-function readContext(Context, observedBits) {
64
+function readContext(Context) {
65
const dispatcher = ReactCurrentDispatcher.current;
66
if (dispatcher === null) {
67
throw new Error(
@@ -70,7 +70,7 @@ function readContext(Context, observedBits) {
70
'lifecycle methods.',
71
);
72
}
73
- return dispatcher.readContext(Context, observedBits);
73
+ return dispatcher.readContext(Context);
74
}
75
76
const CacheContext = createContext(null);
packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js
+2
-13
@@ -736,17 +736,6 @@ describe('ReactDOMServerHooks', () => {
736
},
737
);
738
739
- itRenders('warns when bitmask is passed to useContext', async render => {
740
- const Context = React.createContext('Hi');
741
-
742
- function Foo() {
743
- return <span>{useContext(Context, 1)}</span>;
744
- }
745
-
746
- const domNode = await render(<Foo />, 1);
747
- expect(domNode.textContent).toBe('Hi');
748
- });
749
-
739
describe('useDebugValue', () => {
740
itRenders('is a noop', async render => {
741
function Counter(props) {
@@ -760,11 +749,11 @@ describe('ReactDOMServerHooks', () => {
749
});
750
751
describe('readContext', () => {
763
- function readContext(Context, observedBits) {
752
+ function readContext(Context) {
753
const dispatcher =
754
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
755
.ReactCurrentDispatcher.current;
767
- return dispatcher.readContext(Context, observedBits);
756
+ return dispatcher.readContext(Context);
757
}
758
759
itRenders(
packages/react-dom/src/__tests__/ReactDOMServerIntegrationNewContext-test.js
+2
-2
@@ -161,11 +161,11 @@ describe('ReactDOMServerIntegration', () => {
161
});
162
163
itRenders('readContext() in different components', async render => {
164
- function readContext(Ctx, observedBits) {
164
+ function readContext(Ctx) {
165
const dispatcher =
166
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
167
.ReactCurrentDispatcher.current;
168
- return dispatcher.readContext(Ctx, observedBits);
168
+ return dispatcher.readContext(Ctx);
169
}
170
171
class Cls extends React.Component {
packages/react-dom/src/server/ReactPartialRendererHooks.js
+2
-8
@@ -219,10 +219,7 @@ function getCacheForType<T>(resourceType: () => T): T {
219
invariant(false, 'Not implemented.');
220
}
221
222
-function readContext<T>(
223
- context: ReactContext<T>,
224
- observedBits: void | number | boolean,
225
-): T {
222
+function readContext<T>(context: ReactContext<T>): T {
223
const threadID = currentPartialRenderer.threadID;
224
validateContextBounds(context, threadID);
225
if (__DEV__) {
@@ -238,10 +235,7 @@ function readContext<T>(
235
return context[threadID];
236
}
237
241
-function useContext<T>(
242
- context: ReactContext<T>,
243
- observedBits: void | number | boolean,
244
-): T {
238
+function useContext<T>(context: ReactContext<T>): T {
239
if (__DEV__) {
240
currentHookNameInDev = 'useContext';
241
}
packages/react-reconciler/src/ReactFiberBeginWork.new.js
+6
-23
@@ -160,7 +160,6 @@ import {
160
checkIfContextChanged,
161
readContext,
162
prepareToReadContext,
163
- calculateChangedBits,
163
scheduleWorkOnParentPath,
164
} from './ReactFiberNewContext.new';
165
import {renderWithHooks, bailoutHooks} from './ReactFiberHooks.new';
@@ -221,7 +220,7 @@ import {
220
restoreSpawnedCachePool,
221
getOffscreenDeferredCachePool,
222
} from './ReactFiberCacheComponent.new';
224
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
223
+import is from 'shared/objectIs';
224
225
import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
226
@@ -795,12 +794,7 @@ function updateCacheComponent(
794
pushCacheProvider(workInProgress, nextCache);
795
if (nextCache !== prevState.cache) {
796
// This cache refreshed. Propagate a context change.
798
- propagateContextChange(
799
- workInProgress,
800
- CacheContext,
801
- MAX_SIGNED_31_BIT_INT,
802
- renderLanes,
803
- );
797
+ propagateContextChange(workInProgress, CacheContext, renderLanes);
798
}
799
}
800
}
@@ -1169,12 +1163,7 @@ function updateHostRoot(current, workInProgress, renderLanes) {
1163
pushCacheProvider(workInProgress, nextCache);
1164
if (nextCache !== prevState.cache) {
1165
// The root cache refreshed.
1172
- propagateContextChange(
1173
- workInProgress,
1174
- CacheContext,
1175
- MAX_SIGNED_31_BIT_INT,
1176
- renderLanes,
1177
- );
1166
+ propagateContextChange(workInProgress, CacheContext, renderLanes);
1167
}
1168
}
1169
@@ -3011,8 +3000,7 @@ function updateContextProvider(
3000
} else {
3001
if (oldProps !== null) {
3002
const oldValue = oldProps.value;
3014
- const changedBits = calculateChangedBits(context, newValue, oldValue);
3015
- if (changedBits === 0) {
3003
+ if (is(oldValue, newValue)) {
3004
// No change. Bailout early if children are the same.
3005
if (
3006
oldProps.children === newProps.children &&
@@ -3027,12 +3015,7 @@ function updateContextProvider(
3015
} else {
3016
// The context value changed. Search for matching consumers and schedule
3017
// them to update.
3030
- propagateContextChange(
3031
- workInProgress,
3032
- context,
3033
- changedBits,
3034
- renderLanes,
3035
- );
3018
+ propagateContextChange(workInProgress, context, renderLanes);
3019
}
3020
}
3021
}
@@ -3090,7 +3073,7 @@ function updateContextConsumer(
3073
}
3074
3075
prepareToReadContext(workInProgress, renderLanes);
3093
- const newValue = readContext(context, newProps.unstable_observedBits);
3076
+ const newValue = readContext(context);
3077
let newChildren;
3078
if (__DEV__) {
3079
ReactCurrentOwner.current = workInProgress;
packages/react-reconciler/src/ReactFiberBeginWork.old.js
+6
-23
@@ -160,7 +160,6 @@ import {
160
checkIfContextChanged,
161
readContext,
162
prepareToReadContext,
163
- calculateChangedBits,
163
scheduleWorkOnParentPath,
164
} from './ReactFiberNewContext.old';
165
import {renderWithHooks, bailoutHooks} from './ReactFiberHooks.old';
@@ -221,7 +220,7 @@ import {
220
restoreSpawnedCachePool,
221
getOffscreenDeferredCachePool,
222
} from './ReactFiberCacheComponent.old';
224
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
223
+import is from 'shared/objectIs';
224
225
import {disableLogs, reenableLogs} from 'shared/ConsolePatchingDev';
226
@@ -795,12 +794,7 @@ function updateCacheComponent(
794
pushCacheProvider(workInProgress, nextCache);
795
if (nextCache !== prevState.cache) {
796
// This cache refreshed. Propagate a context change.
798
- propagateContextChange(
799
- workInProgress,
800
- CacheContext,
801
- MAX_SIGNED_31_BIT_INT,
802
- renderLanes,
803
- );
797
+ propagateContextChange(workInProgress, CacheContext, renderLanes);
798
}
799
}
800
}
@@ -1169,12 +1163,7 @@ function updateHostRoot(current, workInProgress, renderLanes) {
1163
pushCacheProvider(workInProgress, nextCache);
1164
if (nextCache !== prevState.cache) {
1165
// The root cache refreshed.
1172
- propagateContextChange(
1173
- workInProgress,
1174
- CacheContext,
1175
- MAX_SIGNED_31_BIT_INT,
1176
- renderLanes,
1177
- );
1166
+ propagateContextChange(workInProgress, CacheContext, renderLanes);
1167
}
1168
}
1169
@@ -3011,8 +3000,7 @@ function updateContextProvider(
3000
} else {
3001
if (oldProps !== null) {
3002
const oldValue = oldProps.value;
3014
- const changedBits = calculateChangedBits(context, newValue, oldValue);
3015
- if (changedBits === 0) {
3003
+ if (is(oldValue, newValue)) {
3004
// No change. Bailout early if children are the same.
3005
if (
3006
oldProps.children === newProps.children &&
@@ -3027,12 +3015,7 @@ function updateContextProvider(
3015
} else {
3016
// The context value changed. Search for matching consumers and schedule
3017
// them to update.
3030
- propagateContextChange(
3031
- workInProgress,
3032
- context,
3033
- changedBits,
3034
- renderLanes,
3035
- );
3018
+ propagateContextChange(workInProgress, context, renderLanes);
3019
}
3020
}
3021
}
@@ -3090,7 +3073,7 @@ function updateContextConsumer(
3073
}
3074
3075
prepareToReadContext(workInProgress, renderLanes);
3093
- const newValue = readContext(context, newProps.unstable_observedBits);
3076
+ const newValue = readContext(context);
3077
let newChildren;
3078
if (__DEV__) {
3079
ReactCurrentOwner.current = workInProgress;
packages/react-reconciler/src/ReactFiberCacheComponent.new.js
-1
@@ -37,7 +37,6 @@ export const CacheContext: ReactContext<Cache> = enableCache
37
// We don't use Consumer/Provider for Cache components. So we'll cheat.
38
Consumer: (null: any),
39
Provider: (null: any),
40
- _calculateChangedBits: null,
40
// We'll initialize these at the root.
41
_currentValue: (null: any),
42
_currentValue2: (null: any),
packages/react-reconciler/src/ReactFiberCacheComponent.old.js
-1
@@ -37,7 +37,6 @@ export const CacheContext: ReactContext<Cache> = enableCache
37
// We don't use Consumer/Provider for Cache components. So we'll cheat.
38
Consumer: (null: any),
39
Provider: (null: any),
40
- _calculateChangedBits: null,
40
// We'll initialize these at the root.
41
_currentValue: (null: any),
42
_currentValue2: (null: any),
packages/react-reconciler/src/ReactFiberHooks.new.js
+28
-70
@@ -2191,11 +2191,8 @@ if (__DEV__) {
2191
};
2192
2193
HooksDispatcherOnMountInDEV = {
2194
- readContext<T>(
2195
- context: ReactContext<T>,
2196
- observedBits: void | number | boolean,
2197
- ): T {
2198
- return readContext(context, observedBits);
2194
+ readContext<T>(context: ReactContext<T>): T {
2195
+ return readContext(context);
2196
},
2197
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2198
currentHookNameInDev = 'useCallback';
@@ -2203,13 +2200,10 @@ if (__DEV__) {
2200
checkDepsAreArrayDev(deps);
2201
return mountCallback(callback, deps);
2202
},
2206
- useContext<T>(
2207
- context: ReactContext<T>,
2208
- observedBits: void | number | boolean,
2209
- ): T {
2203
+ useContext<T>(context: ReactContext<T>): T {
2204
currentHookNameInDev = 'useContext';
2205
mountHookTypesDev();
2212
- return readContext(context, observedBits);
2206
+ return readContext(context);
2207
},
2208
useEffect(
2209
create: () => (() => void) | void,
@@ -2326,24 +2320,18 @@ if (__DEV__) {
2320
}
2321
2322
HooksDispatcherOnMountWithHookTypesInDEV = {
2329
- readContext<T>(
2330
- context: ReactContext<T>,
2331
- observedBits: void | number | boolean,
2332
- ): T {
2333
- return readContext(context, observedBits);
2323
+ readContext<T>(context: ReactContext<T>): T {
2324
+ return readContext(context);
2325
},
2326
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2327
currentHookNameInDev = 'useCallback';
2328
updateHookTypesDev();
2329
return mountCallback(callback, deps);
2330
},
2340
- useContext<T>(
2341
- context: ReactContext<T>,
2342
- observedBits: void | number | boolean,
2343
- ): T {
2331
+ useContext<T>(context: ReactContext<T>): T {
2332
currentHookNameInDev = 'useContext';
2333
updateHookTypesDev();
2346
- return readContext(context, observedBits);
2334
+ return readContext(context);
2335
},
2336
useEffect(
2337
create: () => (() => void) | void,
@@ -2456,24 +2444,18 @@ if (__DEV__) {
2444
}
2445
2446
HooksDispatcherOnUpdateInDEV = {
2459
- readContext<T>(
2460
- context: ReactContext<T>,
2461
- observedBits: void | number | boolean,
2462
- ): T {
2463
- return readContext(context, observedBits);
2447
+ readContext<T>(context: ReactContext<T>): T {
2448
+ return readContext(context);
2449
},
2450
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2451
currentHookNameInDev = 'useCallback';
2452
updateHookTypesDev();
2453
return updateCallback(callback, deps);
2454
},
2470
- useContext<T>(
2471
- context: ReactContext<T>,
2472
- observedBits: void | number | boolean,
2473
- ): T {
2455
+ useContext<T>(context: ReactContext<T>): T {
2456
currentHookNameInDev = 'useContext';
2457
updateHookTypesDev();
2476
- return readContext(context, observedBits);
2458
+ return readContext(context);
2459
},
2460
useEffect(
2461
create: () => (() => void) | void,
@@ -2586,11 +2568,8 @@ if (__DEV__) {
2568
}
2569
2570
HooksDispatcherOnRerenderInDEV = {
2589
- readContext<T>(
2590
- context: ReactContext<T>,
2591
- observedBits: void | number | boolean,
2592
- ): T {
2593
- return readContext(context, observedBits);
2571
+ readContext<T>(context: ReactContext<T>): T {
2572
+ return readContext(context);
2573
},
2574
2575
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
@@ -2598,13 +2577,10 @@ if (__DEV__) {
2577
updateHookTypesDev();
2578
return updateCallback(callback, deps);
2579
},
2601
- useContext<T>(
2602
- context: ReactContext<T>,
2603
- observedBits: void | number | boolean,
2604
- ): T {
2580
+ useContext<T>(context: ReactContext<T>): T {
2581
currentHookNameInDev = 'useContext';
2582
updateHookTypesDev();
2607
- return readContext(context, observedBits);
2583
+ return readContext(context);
2584
},
2585
useEffect(
2586
create: () => (() => void) | void,
@@ -2717,12 +2693,9 @@ if (__DEV__) {
2693
}
2694
2695
InvalidNestedHooksDispatcherOnMountInDEV = {
2720
- readContext<T>(
2721
- context: ReactContext<T>,
2722
- observedBits: void | number | boolean,
2723
- ): T {
2696
+ readContext<T>(context: ReactContext<T>): T {
2697
warnInvalidContextAccess();
2725
- return readContext(context, observedBits);
2698
+ return readContext(context);
2699
},
2700
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2701
currentHookNameInDev = 'useCallback';
@@ -2730,14 +2703,11 @@ if (__DEV__) {
2703
mountHookTypesDev();
2704
return mountCallback(callback, deps);
2705
},
2733
- useContext<T>(
2734
- context: ReactContext<T>,
2735
- observedBits: void | number | boolean,
2736
- ): T {
2706
+ useContext<T>(context: ReactContext<T>): T {
2707
currentHookNameInDev = 'useContext';
2708
warnInvalidHookAccess();
2709
mountHookTypesDev();
2740
- return readContext(context, observedBits);
2710
+ return readContext(context);
2711
},
2712
useEffect(
2713
create: () => (() => void) | void,
@@ -2862,12 +2832,9 @@ if (__DEV__) {
2832
}
2833
2834
InvalidNestedHooksDispatcherOnUpdateInDEV = {
2865
- readContext<T>(
2866
- context: ReactContext<T>,
2867
- observedBits: void | number | boolean,
2868
- ): T {
2835
+ readContext<T>(context: ReactContext<T>): T {
2836
warnInvalidContextAccess();
2870
- return readContext(context, observedBits);
2837
+ return readContext(context);
2838
},
2839
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2840
currentHookNameInDev = 'useCallback';
@@ -2875,14 +2842,11 @@ if (__DEV__) {
2842
updateHookTypesDev();
2843
return updateCallback(callback, deps);
2844
},
2878
- useContext<T>(
2879
- context: ReactContext<T>,
2880
- observedBits: void | number | boolean,
2881
- ): T {
2845
+ useContext<T>(context: ReactContext<T>): T {
2846
currentHookNameInDev = 'useContext';
2847
warnInvalidHookAccess();
2848
updateHookTypesDev();
2885
- return readContext(context, observedBits);
2849
+ return readContext(context);
2850
},
2851
useEffect(
2852
create: () => (() => void) | void,
@@ -3007,12 +2971,9 @@ if (__DEV__) {
2971
}
2972
2973
InvalidNestedHooksDispatcherOnRerenderInDEV = {
3010
- readContext<T>(
3011
- context: ReactContext<T>,
3012
- observedBits: void | number | boolean,
3013
- ): T {
2974
+ readContext<T>(context: ReactContext<T>): T {
2975
warnInvalidContextAccess();
3015
- return readContext(context, observedBits);
2976
+ return readContext(context);
2977
},
2978
2979
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
@@ -3021,14 +2982,11 @@ if (__DEV__) {
2982
updateHookTypesDev();
2983
return updateCallback(callback, deps);
2984
},
3024
- useContext<T>(
3025
- context: ReactContext<T>,
3026
- observedBits: void | number | boolean,
3027
- ): T {
2985
+ useContext<T>(context: ReactContext<T>): T {
2986
currentHookNameInDev = 'useContext';
2987
warnInvalidHookAccess();
2988
updateHookTypesDev();
3031
- return readContext(context, observedBits);
2989
+ return readContext(context);
2990
},
2991
useEffect(
2992
create: () => (() => void) | void,
packages/react-reconciler/src/ReactFiberHooks.old.js
+28
-70
@@ -2191,11 +2191,8 @@ if (__DEV__) {
2191
};
2192
2193
HooksDispatcherOnMountInDEV = {
2194
- readContext<T>(
2195
- context: ReactContext<T>,
2196
- observedBits: void | number | boolean,
2197
- ): T {
2198
- return readContext(context, observedBits);
2194
+ readContext<T>(context: ReactContext<T>): T {
2195
+ return readContext(context);
2196
},
2197
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2198
currentHookNameInDev = 'useCallback';
@@ -2203,13 +2200,10 @@ if (__DEV__) {
2200
checkDepsAreArrayDev(deps);
2201
return mountCallback(callback, deps);
2202
},
2206
- useContext<T>(
2207
- context: ReactContext<T>,
2208
- observedBits: void | number | boolean,
2209
- ): T {
2203
+ useContext<T>(context: ReactContext<T>): T {
2204
currentHookNameInDev = 'useContext';
2205
mountHookTypesDev();
2212
- return readContext(context, observedBits);
2206
+ return readContext(context);
2207
},
2208
useEffect(
2209
create: () => (() => void) | void,
@@ -2326,24 +2320,18 @@ if (__DEV__) {
2320
}
2321
2322
HooksDispatcherOnMountWithHookTypesInDEV = {
2329
- readContext<T>(
2330
- context: ReactContext<T>,
2331
- observedBits: void | number | boolean,
2332
- ): T {
2333
- return readContext(context, observedBits);
2323
+ readContext<T>(context: ReactContext<T>): T {
2324
+ return readContext(context);
2325
},
2326
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2327
currentHookNameInDev = 'useCallback';
2328
updateHookTypesDev();
2329
return mountCallback(callback, deps);
2330
},
2340
- useContext<T>(
2341
- context: ReactContext<T>,
2342
- observedBits: void | number | boolean,
2343
- ): T {
2331
+ useContext<T>(context: ReactContext<T>): T {
2332
currentHookNameInDev = 'useContext';
2333
updateHookTypesDev();
2346
- return readContext(context, observedBits);
2334
+ return readContext(context);
2335
},
2336
useEffect(
2337
create: () => (() => void) | void,
@@ -2456,24 +2444,18 @@ if (__DEV__) {
2444
}
2445
2446
HooksDispatcherOnUpdateInDEV = {
2459
- readContext<T>(
2460
- context: ReactContext<T>,
2461
- observedBits: void | number | boolean,
2462
- ): T {
2463
- return readContext(context, observedBits);
2447
+ readContext<T>(context: ReactContext<T>): T {
2448
+ return readContext(context);
2449
},
2450
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2451
currentHookNameInDev = 'useCallback';
2452
updateHookTypesDev();
2453
return updateCallback(callback, deps);
2454
},
2470
- useContext<T>(
2471
- context: ReactContext<T>,
2472
- observedBits: void | number | boolean,
2473
- ): T {
2455
+ useContext<T>(context: ReactContext<T>): T {
2456
currentHookNameInDev = 'useContext';
2457
updateHookTypesDev();
2476
- return readContext(context, observedBits);
2458
+ return readContext(context);
2459
},
2460
useEffect(
2461
create: () => (() => void) | void,
@@ -2586,11 +2568,8 @@ if (__DEV__) {
2568
}
2569
2570
HooksDispatcherOnRerenderInDEV = {
2589
- readContext<T>(
2590
- context: ReactContext<T>,
2591
- observedBits: void | number | boolean,
2592
- ): T {
2593
- return readContext(context, observedBits);
2571
+ readContext<T>(context: ReactContext<T>): T {
2572
+ return readContext(context);
2573
},
2574
2575
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
@@ -2598,13 +2577,10 @@ if (__DEV__) {
2577
updateHookTypesDev();
2578
return updateCallback(callback, deps);
2579
},
2601
- useContext<T>(
2602
- context: ReactContext<T>,
2603
- observedBits: void | number | boolean,
2604
- ): T {
2580
+ useContext<T>(context: ReactContext<T>): T {
2581
currentHookNameInDev = 'useContext';
2582
updateHookTypesDev();
2607
- return readContext(context, observedBits);
2583
+ return readContext(context);
2584
},
2585
useEffect(
2586
create: () => (() => void) | void,
@@ -2717,12 +2693,9 @@ if (__DEV__) {
2693
}
2694
2695
InvalidNestedHooksDispatcherOnMountInDEV = {
2720
- readContext<T>(
2721
- context: ReactContext<T>,
2722
- observedBits: void | number | boolean,
2723
- ): T {
2696
+ readContext<T>(context: ReactContext<T>): T {
2697
warnInvalidContextAccess();
2725
- return readContext(context, observedBits);
2698
+ return readContext(context);
2699
},
2700
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2701
currentHookNameInDev = 'useCallback';
@@ -2730,14 +2703,11 @@ if (__DEV__) {
2703
mountHookTypesDev();
2704
return mountCallback(callback, deps);
2705
},
2733
- useContext<T>(
2734
- context: ReactContext<T>,
2735
- observedBits: void | number | boolean,
2736
- ): T {
2706
+ useContext<T>(context: ReactContext<T>): T {
2707
currentHookNameInDev = 'useContext';
2708
warnInvalidHookAccess();
2709
mountHookTypesDev();
2740
- return readContext(context, observedBits);
2710
+ return readContext(context);
2711
},
2712
useEffect(
2713
create: () => (() => void) | void,
@@ -2862,12 +2832,9 @@ if (__DEV__) {
2832
}
2833
2834
InvalidNestedHooksDispatcherOnUpdateInDEV = {
2865
- readContext<T>(
2866
- context: ReactContext<T>,
2867
- observedBits: void | number | boolean,
2868
- ): T {
2835
+ readContext<T>(context: ReactContext<T>): T {
2836
warnInvalidContextAccess();
2870
- return readContext(context, observedBits);
2837
+ return readContext(context);
2838
},
2839
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
2840
currentHookNameInDev = 'useCallback';
@@ -2875,14 +2842,11 @@ if (__DEV__) {
2842
updateHookTypesDev();
2843
return updateCallback(callback, deps);
2844
},
2878
- useContext<T>(
2879
- context: ReactContext<T>,
2880
- observedBits: void | number | boolean,
2881
- ): T {
2845
+ useContext<T>(context: ReactContext<T>): T {
2846
currentHookNameInDev = 'useContext';
2847
warnInvalidHookAccess();
2848
updateHookTypesDev();
2885
- return readContext(context, observedBits);
2849
+ return readContext(context);
2850
},
2851
useEffect(
2852
create: () => (() => void) | void,
@@ -3007,12 +2971,9 @@ if (__DEV__) {
2971
}
2972
2973
InvalidNestedHooksDispatcherOnRerenderInDEV = {
3010
- readContext<T>(
3011
- context: ReactContext<T>,
3012
- observedBits: void | number | boolean,
3013
- ): T {
2974
+ readContext<T>(context: ReactContext<T>): T {
2975
warnInvalidContextAccess();
3015
- return readContext(context, observedBits);
2976
+ return readContext(context);
2977
},
2978
2979
useCallback<T>(callback: T, deps: Array<mixed> | void | null): T {
@@ -3021,14 +2982,11 @@ if (__DEV__) {
2982
updateHookTypesDev();
2983
return updateCallback(callback, deps);
2984
},
3024
- useContext<T>(
3025
- context: ReactContext<T>,
3026
- observedBits: void | number | boolean,
3027
- ): T {
2985
+ useContext<T>(context: ReactContext<T>): T {
2986
currentHookNameInDev = 'useContext';
2987
warnInvalidHookAccess();
2988
updateHookTypesDev();
3031
- return readContext(context, observedBits);
2989
+ return readContext(context);
2990
},
2991
useEffect(
2992
create: () => (() => void) | void,
packages/react-reconciler/src/ReactFiberNewContext.new.js
+13
-74
@@ -19,7 +19,6 @@ import type {SharedQueue} from './ReactUpdateQueue.new';
19
20
import {isPrimaryRenderer} from './ReactFiberHostConfig';
21
import {createCursor, push, pop} from './ReactFiberStack.new';
22
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
22
import {
23
ContextProvider,
24
ClassComponent,
@@ -58,7 +57,7 @@ if (__DEV__) {
57
58
let currentlyRenderingFiber: Fiber | null = null;
59
let lastContextDependency: ContextDependency<mixed> | null = null;
61
-let lastContextWithAllBitsObserved: ReactContext<any> | null = null;
60
+let lastFullyObservedContext: ReactContext<any> | null = null;
61
62
let isDisallowedContextReadInDEV: boolean = false;
63
@@ -67,7 +66,7 @@ export function resetContextDependencies(): void {
66
// cannot be called outside the render phase.
67
currentlyRenderingFiber = null;
68
lastContextDependency = null;
70
- lastContextWithAllBitsObserved = null;
69
+ lastFullyObservedContext = null;
70
if (__DEV__) {
71
isDisallowedContextReadInDEV = false;
72
}
@@ -140,33 +139,6 @@ export function popProvider(
139
}
140
}
141
143
-export function calculateChangedBits<T>(
144
- context: ReactContext<T>,
145
- newValue: T,
146
- oldValue: T,
147
-) {
148
- if (is(oldValue, newValue)) {
149
- // No change
150
- return 0;
151
- } else {
152
- const changedBits =
153
- typeof context._calculateChangedBits === 'function'
154
- ? context._calculateChangedBits(oldValue, newValue)
155
- : MAX_SIGNED_31_BIT_INT;
156
-
157
- if (__DEV__) {
158
- if ((changedBits & MAX_SIGNED_31_BIT_INT) !== changedBits) {
159
- console.error(
160
- 'calculateChangedBits: Expected the return value to be a ' +
161
- '31-bit integer. Instead received: %s',
162
- changedBits,
163
- );
164
- }
165
- }
166
- return changedBits | 0;
167
- }
168
-}
169
-
142
export function scheduleWorkOnParentPath(
143
parent: Fiber | null,
144
renderLanes: Lanes,
@@ -197,7 +169,6 @@ export function scheduleWorkOnParentPath(
169
export function propagateContextChange<T>(
170
workInProgress: Fiber,
171
context: ReactContext<T>,
200
- changedBits: number,
172
renderLanes: Lanes,
173
): void {
174
if (enableLazyContextPropagation) {
@@ -207,24 +178,18 @@ export function propagateContextChange<T>(
178
const forcePropagateEntireTree = true;
179
propagateContextChanges(
180
workInProgress,
210
- [context, changedBits],
181
+ [context],
182
renderLanes,
183
forcePropagateEntireTree,
184
);
185
} else {
215
- propagateContextChange_eager(
216
- workInProgress,
217
- context,
218
- changedBits,
219
- renderLanes,
220
- );
186
+ propagateContextChange_eager(workInProgress, context, renderLanes);
187
}
188
}
189
190
function propagateContextChange_eager<T>(
191
workInProgress: Fiber,
192
context: ReactContext<T>,
227
- changedBits: number,
193
renderLanes: Lanes,
194
): void {
195
// Only used by eager implemenation
@@ -247,10 +212,7 @@ function propagateContextChange_eager<T>(
212
let dependency = list.firstContext;
213
while (dependency !== null) {
214
// Check if the context matches.
250
- if (
251
- dependency.context === context &&
252
- (dependency.observedBits & changedBits) !== 0
253
- ) {
215
+ if (dependency.context === context) {
216
// Match! Schedule an update on this fiber.
217
if (fiber.tag === ClassComponent) {
218
// Schedule a force update on the work-in-progress.
@@ -382,15 +344,11 @@ function propagateContextChanges<T>(
344
// Assigning these to constants to help Flow
345
const dependency = dep;
346
const consumer = fiber;
385
- findContext: for (let i = 0; i < contexts.length; i += 2) {
347
+ findContext: for (let i = 0; i < contexts.length; i++) {
348
const context: ReactContext<T> = contexts[i];
387
- const changedBits: number = contexts[i + 1];
349
// Check if the context matches.
350
// TODO: Compare selected values to bail out early.
390
- if (
391
- dependency.context === context &&
392
- (dependency.observedBits & changedBits) !== 0
393
- ) {
351
+ if (dependency.context === context) {
352
// Match! Schedule an update on this fiber.
353
354
// In the lazy implemenation, don't mark a dirty flag on the
@@ -549,12 +507,11 @@ function propagateParentContextChanges(
507
508
const oldValue = oldProps.value;
509
552
- const changedBits = calculateChangedBits(context, newValue, oldValue);
553
- if (changedBits !== 0) {
510
+ if (!is(newValue, oldValue)) {
511
if (contexts !== null) {
555
- contexts.push(context, changedBits);
512
+ contexts.push(context);
513
} else {
557
- contexts = [context, changedBits];
514
+ contexts = [context];
515
}
516
}
517
}
@@ -625,7 +582,7 @@ export function prepareToReadContext(
582
): void {
583
currentlyRenderingFiber = workInProgress;
584
lastContextDependency = null;
628
- lastContextWithAllBitsObserved = null;
585
+ lastFullyObservedContext = null;
586
587
const dependencies = workInProgress.dependencies;
588
if (dependencies !== null) {
@@ -646,10 +603,7 @@ export function prepareToReadContext(
603
}
604
}
605
649
-export function readContext<T>(
650
- context: ReactContext<T>,
651
- observedBits: void | number | boolean,
652
-): T {
606
+export function readContext<T>(context: ReactContext<T>): T {
607
if (__DEV__) {
608
// This warning would fire if you read context inside a Hook like useMemo.
609
// Unlike the class check below, it's not enforced in production for perf.
@@ -667,26 +621,11 @@ export function readContext<T>(
621
? context._currentValue
622
: context._currentValue2;
623
670
- if (lastContextWithAllBitsObserved === context) {
624
+ if (lastFullyObservedContext === context) {
625
// Nothing to do. We already observe everything in this context.
672
- } else if (observedBits === false || observedBits === 0) {
673
- // Do not observe any updates.
626
} else {
675
- let resolvedObservedBits; // Avoid deopting on observable arguments or heterogeneous types.
676
- if (
677
- typeof observedBits !== 'number' ||
678
- observedBits === MAX_SIGNED_31_BIT_INT
679
- ) {
680
- // Observe all updates.
681
- lastContextWithAllBitsObserved = ((context: any): ReactContext<mixed>);
682
- resolvedObservedBits = MAX_SIGNED_31_BIT_INT;
683
- } else {
684
- resolvedObservedBits = observedBits;
685
- }
686
-
627
const contextItem = {
628
context: ((context: any): ReactContext<mixed>),
689
- observedBits: resolvedObservedBits,
629
memoizedValue: value,
630
next: null,
631
};
packages/react-reconciler/src/ReactFiberNewContext.old.js
+13
-74
@@ -19,7 +19,6 @@ import type {SharedQueue} from './ReactUpdateQueue.old';
19
20
import {isPrimaryRenderer} from './ReactFiberHostConfig';
21
import {createCursor, push, pop} from './ReactFiberStack.old';
22
-import {MAX_SIGNED_31_BIT_INT} from './MaxInts';
22
import {
23
ContextProvider,
24
ClassComponent,
@@ -58,7 +57,7 @@ if (__DEV__) {
57
58
let currentlyRenderingFiber: Fiber | null = null;
59
let lastContextDependency: ContextDependency<mixed> | null = null;
61
-let lastContextWithAllBitsObserved: ReactContext<any> | null = null;
60
+let lastFullyObservedContext: ReactContext<any> | null = null;
61
62
let isDisallowedContextReadInDEV: boolean = false;
63
@@ -67,7 +66,7 @@ export function resetContextDependencies(): void {
66
// cannot be called outside the render phase.
67
currentlyRenderingFiber = null;
68
lastContextDependency = null;
70
- lastContextWithAllBitsObserved = null;
69
+ lastFullyObservedContext = null;
70
if (__DEV__) {
71
isDisallowedContextReadInDEV = false;
72
}
@@ -140,33 +139,6 @@ export function popProvider(
139
}
140
}
141
143
-export function calculateChangedBits<T>(
144
- context: ReactContext<T>,
145
- newValue: T,
146
- oldValue: T,
147
-) {
148
- if (is(oldValue, newValue)) {
149
- // No change
150
- return 0;
151
- } else {
152
- const changedBits =
153
- typeof context._calculateChangedBits === 'function'
154
- ? context._calculateChangedBits(oldValue, newValue)
155
- : MAX_SIGNED_31_BIT_INT;
156
-
157
- if (__DEV__) {
158
- if ((changedBits & MAX_SIGNED_31_BIT_INT) !== changedBits) {
159
- console.error(
160
- 'calculateChangedBits: Expected the return value to be a ' +
161
- '31-bit integer. Instead received: %s',
162
- changedBits,
163
- );
164
- }
165
- }
166
- return changedBits | 0;
167
- }
168
-}
169
-
142
export function scheduleWorkOnParentPath(
143
parent: Fiber | null,
144
renderLanes: Lanes,
@@ -197,7 +169,6 @@ export function scheduleWorkOnParentPath(
169
export function propagateContextChange<T>(
170
workInProgress: Fiber,
171
context: ReactContext<T>,
200
- changedBits: number,
172
renderLanes: Lanes,
173
): void {
174
if (enableLazyContextPropagation) {
@@ -207,24 +178,18 @@ export function propagateContextChange<T>(
178
const forcePropagateEntireTree = true;
179
propagateContextChanges(
180
workInProgress,
210
- [context, changedBits],
181
+ [context],
182
renderLanes,
183
forcePropagateEntireTree,
184
);
185
} else {
215
- propagateContextChange_eager(
216
- workInProgress,
217
- context,
218
- changedBits,
219
- renderLanes,
220
- );
186
+ propagateContextChange_eager(workInProgress, context, renderLanes);
187
}
188
}
189
190
function propagateContextChange_eager<T>(
191
workInProgress: Fiber,
192
context: ReactContext<T>,
227
- changedBits: number,
193
renderLanes: Lanes,
194
): void {
195
// Only used by eager implemenation
@@ -247,10 +212,7 @@ function propagateContextChange_eager<T>(
212
let dependency = list.firstContext;
213
while (dependency !== null) {
214
// Check if the context matches.
250
- if (
251
- dependency.context === context &&
252
- (dependency.observedBits & changedBits) !== 0
253
- ) {
215
+ if (dependency.context === context) {
216
// Match! Schedule an update on this fiber.
217
if (fiber.tag === ClassComponent) {
218
// Schedule a force update on the work-in-progress.
@@ -382,15 +344,11 @@ function propagateContextChanges<T>(
344
// Assigning these to constants to help Flow
345
const dependency = dep;
346
const consumer = fiber;
385
- findContext: for (let i = 0; i < contexts.length; i += 2) {
347
+ findContext: for (let i = 0; i < contexts.length; i++) {
348
const context: ReactContext<T> = contexts[i];
387
- const changedBits: number = contexts[i + 1];
349
// Check if the context matches.
350
// TODO: Compare selected values to bail out early.
390
- if (
391
- dependency.context === context &&
392
- (dependency.observedBits & changedBits) !== 0
393
- ) {
351
+ if (dependency.context === context) {
352
// Match! Schedule an update on this fiber.
353
354
// In the lazy implemenation, don't mark a dirty flag on the
@@ -549,12 +507,11 @@ function propagateParentContextChanges(
507
508
const oldValue = oldProps.value;
509
552
- const changedBits = calculateChangedBits(context, newValue, oldValue);
553
- if (changedBits !== 0) {
510
+ if (!is(newValue, oldValue)) {
511
if (contexts !== null) {
555
- contexts.push(context, changedBits);
512
+ contexts.push(context);
513
} else {
557
- contexts = [context, changedBits];
514
+ contexts = [context];
515
}
516
}
517
}
@@ -625,7 +582,7 @@ export function prepareToReadContext(
582
): void {
583
currentlyRenderingFiber = workInProgress;
584
lastContextDependency = null;
628
- lastContextWithAllBitsObserved = null;
585
+ lastFullyObservedContext = null;
586
587
const dependencies = workInProgress.dependencies;
588
if (dependencies !== null) {
@@ -646,10 +603,7 @@ export function prepareToReadContext(
603
}
604
}
605
649
-export function readContext<T>(
650
- context: ReactContext<T>,
651
- observedBits: void | number | boolean,
652
-): T {
606
+export function readContext<T>(context: ReactContext<T>): T {
607
if (__DEV__) {
608
// This warning would fire if you read context inside a Hook like useMemo.
609
// Unlike the class check below, it's not enforced in production for perf.
@@ -667,26 +621,11 @@ export function readContext<T>(
621
? context._currentValue
622
: context._currentValue2;
623
670
- if (lastContextWithAllBitsObserved === context) {
624
+ if (lastFullyObservedContext === context) {
625
// Nothing to do. We already observe everything in this context.
672
- } else if (observedBits === false || observedBits === 0) {
673
- // Do not observe any updates.
626
} else {
675
- let resolvedObservedBits; // Avoid deopting on observable arguments or heterogeneous types.
676
- if (
677
- typeof observedBits !== 'number' ||
678
- observedBits === MAX_SIGNED_31_BIT_INT
679
- ) {
680
- // Observe all updates.
681
- lastContextWithAllBitsObserved = ((context: any): ReactContext<mixed>);
682
- resolvedObservedBits = MAX_SIGNED_31_BIT_INT;
683
- } else {
684
- resolvedObservedBits = observedBits;
685
- }
686
-
627
const contextItem = {
628
context: ((context: any): ReactContext<mixed>),
689
- observedBits: resolvedObservedBits,
629
memoizedValue: value,
630
next: null,
631
};
packages/react-reconciler/src/ReactInternalTypes.js
+2
-9
@@ -49,7 +49,6 @@ export type ReactPriorityLevel = 99 | 98 | 97 | 96 | 95 | 90;
49
50
export type ContextDependency<T> = {
51
context: ReactContext<T>,
52
- observedBits: number,
52
next: ContextDependency<mixed> | null,
53
memoizedValue: T,
54
...
@@ -281,20 +280,14 @@ type Dispatch<A> = A => void;
280
281
export type Dispatcher = {|
282
getCacheForType?: <T>(resourceType: () => T) => T,
284
- readContext<T>(
285
- context: ReactContext<T>,
286
- observedBits: void | number | boolean,
287
- ): T,
283
+ readContext<T>(context: ReactContext<T>): T,
284
useState<S>(initialState: (() => S) | S): [S, Dispatch<BasicStateAction<S>>],
285
useReducer<S, I, A>(
286
reducer: (S, A) => S,
287
initialArg: I,
288
init?: (I) => S,
289
): [S, Dispatch<A>],
294
- useContext<T>(
295
- context: ReactContext<T>,
296
- observedBits: void | number | boolean,
297
- ): T,
290
+ useContext<T>(context: ReactContext<T>): T,
291
useRef<T>(initialValue: T): {|current: T|},
292
useEffect(
293
create: () => (() => void) | void,
packages/react-reconciler/src/__tests__/ReactNewContext-test.js
+10
-297
@@ -35,11 +35,11 @@ describe('ReactNewContext', () => {
35
return {type: 'span', children: [], prop, hidden: false};
36
}
37
38
- function readContext(Context, observedBits) {
38
+ function readContext(Context) {
39
const dispatcher =
40
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
41
.ReactCurrentDispatcher.current;
42
- return dispatcher.readContext(Context, observedBits);
42
+ return dispatcher.readContext(Context);
43
}
44
45
// Note: This is based on a similar component we use in www. We can delete
@@ -62,48 +62,21 @@ describe('ReactNewContext', () => {
62
'useContext inside function component',
63
Context =>
64
function Consumer(props) {
65
- const observedBits = props.unstable_observedBits;
66
- let contextValue;
67
- expect(() => {
68
- contextValue = useContext(Context, observedBits);
69
- }).toErrorDev(
70
- observedBits !== undefined
71
- ? 'useContext() second argument is reserved for future use in React. ' +
72
- `Passing it is not supported. You passed: ${observedBits}.`
73
- : [],
74
- );
65
+ const contextValue = useContext(Context);
66
const render = props.children;
67
return render(contextValue);
68
},
69
);
70
sharedContextTests('useContext inside forwardRef component', Context =>
71
React.forwardRef(function Consumer(props, ref) {
81
- const observedBits = props.unstable_observedBits;
82
- let contextValue;
83
- expect(() => {
84
- contextValue = useContext(Context, observedBits);
85
- }).toErrorDev(
86
- observedBits !== undefined
87
- ? 'useContext() second argument is reserved for future use in React. ' +
88
- `Passing it is not supported. You passed: ${observedBits}.`
89
- : [],
90
- );
72
+ const contextValue = useContext(Context);
73
const render = props.children;
74
return render(contextValue);
75
}),
76
);
77
sharedContextTests('useContext inside memoized function component', Context =>
78
React.memo(function Consumer(props) {
97
- const observedBits = props.unstable_observedBits;
98
- let contextValue;
99
- expect(() => {
100
- contextValue = useContext(Context, observedBits);
101
- }).toErrorDev(
102
- observedBits !== undefined
103
- ? 'useContext() second argument is reserved for future use in React. ' +
104
- `Passing it is not supported. You passed: ${observedBits}.`
105
- : [],
106
- );
79
+ const contextValue = useContext(Context);
80
const render = props.children;
81
return render(contextValue);
82
}),
@@ -113,8 +86,7 @@ describe('ReactNewContext', () => {
86
Context =>
87
class Consumer extends React.Component {
88
render() {
116
- const observedBits = this.props.unstable_observedBits;
117
- const contextValue = readContext(Context, observedBits);
89
+ const contextValue = readContext(Context);
90
const render = this.props.children;
91
return render(contextValue);
92
}
@@ -125,8 +97,7 @@ describe('ReactNewContext', () => {
97
Context =>
98
class Consumer extends React.PureComponent {
99
render() {
128
- const observedBits = this.props.unstable_observedBits;
129
- const contextValue = readContext(Context, observedBits);
100
+ const contextValue = readContext(Context);
101
const render = this.props.children;
102
return render(contextValue);
103
}
@@ -590,227 +561,6 @@ describe('ReactNewContext', () => {
561
]);
562
});
563
593
- it('can skip consumers with bitmask', () => {
594
- const Context = React.createContext({foo: 0, bar: 0}, (a, b) => {
595
- let result = 0;
596
- if (a.foo !== b.foo) {
597
- result |= 0b01;
598
- }
599
- if (a.bar !== b.bar) {
600
- result |= 0b10;
601
- }
602
- return result;
603
- });
604
- const Consumer = getConsumer(Context);
605
-
606
- function Provider(props) {
607
- return (
608
- <Context.Provider value={{foo: props.foo, bar: props.bar}}>
609
- {props.children}
610
- </Context.Provider>
611
- );
612
- }
613
-
614
- function Foo() {
615
- return (
616
- <Consumer unstable_observedBits={0b01}>
617
- {value => {
618
- Scheduler.unstable_yieldValue('Foo');
619
- return <span prop={'Foo: ' + value.foo} />;
620
- }}
621
- </Consumer>
622
- );
623
- }
624
-
625
- function Bar() {
626
- return (
627
- <Consumer unstable_observedBits={0b10}>
628
- {value => {
629
- Scheduler.unstable_yieldValue('Bar');
630
- return <span prop={'Bar: ' + value.bar} />;
631
- }}
632
- </Consumer>
633
- );
634
- }
635
-
636
- class Indirection extends React.Component {
637
- shouldComponentUpdate() {
638
- return false;
639
- }
640
- render() {
641
- return this.props.children;
642
- }
643
- }
644
-
645
- function App(props) {
646
- return (
647
- <Provider foo={props.foo} bar={props.bar}>
648
- <Indirection>
649
- <Indirection>
650
- <Foo />
651
- </Indirection>
652
- <Indirection>
653
- <Bar />
654
- </Indirection>
655
- </Indirection>
656
- </Provider>
657
- );
658
- }
659
-
660
- ReactNoop.render(<App foo={1} bar={1} />);
661
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar']);
662
- expect(ReactNoop.getChildren()).toEqual([
663
- span('Foo: 1'),
664
- span('Bar: 1'),
665
- ]);
666
-
667
- // Update only foo
668
- ReactNoop.render(<App foo={2} bar={1} />);
669
- expect(Scheduler).toFlushAndYield(['Foo']);
670
- expect(ReactNoop.getChildren()).toEqual([
671
- span('Foo: 2'),
672
- span('Bar: 1'),
673
- ]);
674
-
675
- // Update only bar
676
- ReactNoop.render(<App foo={2} bar={2} />);
677
- expect(Scheduler).toFlushAndYield(['Bar']);
678
- expect(ReactNoop.getChildren()).toEqual([
679
- span('Foo: 2'),
680
- span('Bar: 2'),
681
- ]);
682
-
683
- // Update both
684
- ReactNoop.render(<App foo={3} bar={3} />);
685
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar']);
686
- expect(ReactNoop.getChildren()).toEqual([
687
- span('Foo: 3'),
688
- span('Bar: 3'),
689
- ]);
690
- });
691
-
692
- // @gate !enableLazyContextPropagation
693
- it('can skip parents with bitmask bailout while updating their children', () => {
694
- const Context = React.createContext({foo: 0, bar: 0}, (a, b) => {
695
- let result = 0;
696
- if (a.foo !== b.foo) {
697
- result |= 0b01;
698
- }
699
- if (a.bar !== b.bar) {
700
- result |= 0b10;
701
- }
702
- return result;
703
- });
704
- const Consumer = getConsumer(Context);
705
-
706
- function Provider(props) {
707
- return (
708
- <Context.Provider value={{foo: props.foo, bar: props.bar}}>
709
- {props.children}
710
- </Context.Provider>
711
- );
712
- }
713
-
714
- function Foo(props) {
715
- return (
716
- <Consumer unstable_observedBits={0b01}>
717
- {value => {
718
- Scheduler.unstable_yieldValue('Foo');
719
- return (
720
- <>
721
- <span prop={'Foo: ' + value.foo} />
722
- {props.children && props.children()}
723
- </>
724
- );
725
- }}
726
- </Consumer>
727
- );
728
- }
729
-
730
- function Bar(props) {
731
- return (
732
- <Consumer unstable_observedBits={0b10}>
733
- {value => {
734
- Scheduler.unstable_yieldValue('Bar');
735
- return (
736
- <>
737
- <span prop={'Bar: ' + value.bar} />
738
- {props.children && props.children()}
739
- </>
740
- );
741
- }}
742
- </Consumer>
743
- );
744
- }
745
-
746
- class Indirection extends React.Component {
747
- shouldComponentUpdate() {
748
- return false;
749
- }
750
- render() {
751
- return this.props.children;
752
- }
753
- }
754
-
755
- function App(props) {
756
- return (
757
- <Provider foo={props.foo} bar={props.bar}>
758
- <Indirection>
759
- <Foo>
760
- {/* Use a render prop so we don't test constant elements. */}
761
- {() => (
762
- <Indirection>
763
- <Bar>
764
- {() => (
765
- <Indirection>
766
- <Foo />
767
- </Indirection>
768
- )}
769
- </Bar>
770
- </Indirection>
771
- )}
772
- </Foo>
773
- </Indirection>
774
- </Provider>
775
- );
776
- }
777
-
778
- ReactNoop.render(<App foo={1} bar={1} />);
779
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar', 'Foo']);
780
- expect(ReactNoop.getChildren()).toEqual([
781
- span('Foo: 1'),
782
- span('Bar: 1'),
783
- span('Foo: 1'),
784
- ]);
785
-
786
- // Update only foo
787
- ReactNoop.render(<App foo={2} bar={1} />);
788
- expect(Scheduler).toFlushAndYield(['Foo', 'Foo']);
789
- expect(ReactNoop.getChildren()).toEqual([
790
- span('Foo: 2'),
791
- span('Bar: 1'),
792
- span('Foo: 2'),
793
- ]);
794
-
795
- // Update only bar
796
- ReactNoop.render(<App foo={2} bar={2} />);
797
- expect(Scheduler).toFlushAndYield(['Bar']);
798
- expect(ReactNoop.getChildren()).toEqual([
799
- span('Foo: 2'),
800
- span('Bar: 2'),
801
- span('Foo: 2'),
802
- ]);
803
-
804
- // Update both
805
- ReactNoop.render(<App foo={3} bar={3} />);
806
- expect(Scheduler).toFlushAndYield(['Foo', 'Bar', 'Foo']);
807
- expect(ReactNoop.getChildren()).toEqual([
808
- span('Foo: 3'),
809
- span('Bar: 3'),
810
- span('Foo: 3'),
811
- ]);
812
- });
813
-
564
it("does not re-render if there's an update in a child", () => {
565
const Context = React.createContext(0);
566
const Consumer = getConsumer(Context);
@@ -1063,30 +813,6 @@ describe('ReactNewContext', () => {
813
}
814
815
describe('Context.Provider', () => {
1066
- it('warns if calculateChangedBits returns larger than a 31-bit integer', () => {
1067
- const Context = React.createContext(
1068
- 0,
1069
- (a, b) => Math.pow(2, 32) - 1, // Return 32 bit int
1070
- );
1071
-
1072
- function App(props) {
1073
- return <Context.Provider value={props.value} />;
1074
- }
1075
-
1076
- ReactNoop.render(<App value={1} />);
1077
- expect(Scheduler).toFlushWithoutYielding();
1078
-
1079
- // Update
1080
- ReactNoop.render(<App value={2} />);
1081
-
1082
- if (gate(flags => !flags.enableLazyContextPropagation)) {
1083
- expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
1084
- 'calculateChangedBits: Expected the return value to be a 31-bit ' +
1085
- 'integer. Instead received: 4294967295',
1086
- );
1087
- }
1088
- });
1089
-
816
it('warns if no value prop provided', () => {
817
const Context = React.createContext();
818
@@ -1355,6 +1081,9 @@ describe('ReactNewContext', () => {
1081
});
1082
1083
describe('readContext', () => {
1084
+ // Unstable changedBits API was removed. Port this test to context selectors
1085
+ // once that exists.
1086
+ // @gate FIXME
1087
it('can read the same context multiple times in the same function', () => {
1088
const Context = React.createContext({foo: 0, bar: 0, baz: 0}, (a, b) => {
1089
let result = 0;
@@ -1517,22 +1246,6 @@ describe('ReactNewContext', () => {
1246
});
1247
1248
describe('useContext', () => {
1520
- it('warns on array.map(useContext)', () => {
1521
- const Context = React.createContext(0);
1522
- function Foo() {
1523
- return [Context].map(useContext);
1524
- }
1525
- ReactNoop.render(<Foo />);
1526
- expect(() => expect(Scheduler).toFlushWithoutYielding()).toErrorDev(
1527
- 'useContext() second argument is reserved for future ' +
1528
- 'use in React. Passing it is not supported. ' +
1529
- 'You passed: 0.\n\n' +
1530
- 'Did you call array.map(useContext)? ' +
1531
- 'Calling Hooks inside a loop is not supported. ' +
1532
- 'Learn more at https://reactjs.org/link/rules-of-hooks',
1533
- );
1534
- });
1535
-
1249
it('throws when used in a class component', () => {
1250
const Context = React.createContext(0);
1251
class Foo extends React.Component {
packages/react/src/ReactContext.js
+3
-22
@@ -11,30 +11,12 @@ import {REACT_PROVIDER_TYPE, REACT_CONTEXT_TYPE} from 'shared/ReactSymbols';
11
12
import type {ReactContext} from 'shared/ReactTypes';
13
14
-export function createContext<T>(
15
- defaultValue: T,
16
- calculateChangedBits: ?(a: T, b: T) => number,
17
-): ReactContext<T> {
18
- if (calculateChangedBits === undefined) {
19
- calculateChangedBits = null;
20
- } else {
21
- if (__DEV__) {
22
- if (
23
- calculateChangedBits !== null &&
24
- typeof calculateChangedBits !== 'function'
25
- ) {
26
- console.error(
27
- 'createContext: Expected the optional second argument to be a ' +
28
- 'function. Instead received: %s',
29
- calculateChangedBits,
30
- );
31
- }
32
- }
33
- }
14
+export function createContext<T>(defaultValue: T): ReactContext<T> {
15
+ // TODO: Second argument used to be an optional `calculateChangedBits`
16
+ // function. Warn to reserve for future use?
17
18
const context: ReactContext<T> = {
19
$$typeof: REACT_CONTEXT_TYPE,
37
- _calculateChangedBits: calculateChangedBits,
20
// As a workaround to support multiple concurrent renderers, we categorize
21
// some renderers as primary and others as secondary. We only expect
22
// there to be two concurrent renderers at most: React Native (primary) and
@@ -66,7 +48,6 @@ export function createContext<T>(
48
const Consumer = {
49
$$typeof: REACT_CONTEXT_TYPE,
50
_context: context,
69
- _calculateChangedBits: context._calculateChangedBits,
51
};
52
// $FlowFixMe: Flow complains about not setting a value, which is intentional here
53
Object.defineProperties(Consumer, {
packages/react/src/ReactHooks.js
+2
-19
@@ -47,26 +47,9 @@ export function getCacheForType<T>(resourceType: () => T): T {
47
return dispatcher.getCacheForType(resourceType);
48
}
49
50
-export function useContext<T>(
51
- Context: ReactContext<T>,
52
- unstable_observedBits: number | boolean | void,
53
-): T {
50
+export function useContext<T>(Context: ReactContext<T>): T {
51
const dispatcher = resolveDispatcher();
52
if (__DEV__) {
56
- if (unstable_observedBits !== undefined) {
57
- console.error(
58
- 'useContext() second argument is reserved for future ' +
59
- 'use in React. Passing it is not supported. ' +
60
- 'You passed: %s.%s',
61
- unstable_observedBits,
62
- typeof unstable_observedBits === 'number' && Array.isArray(arguments[2])
63
- ? '\n\nDid you call array.map(useContext)? ' +
64
- 'Calling Hooks inside a loop is not supported. ' +
65
- 'Learn more at https://reactjs.org/link/rules-of-hooks'
66
- : '',
67
- );
68
- }
69
-
53
// TODO: add a more generic warning for invalid values.
54
if ((Context: any)._context !== undefined) {
55
const realContext = (Context: any)._context;
@@ -85,7 +68,7 @@ export function useContext<T>(
68
}
69
}
70
}
88
- return dispatcher.useContext(Context, unstable_observedBits);
71
+ return dispatcher.useContext(Context);
72
}
73
74
export function useState<S>(
packages/shared/ReactTypes.js
-2
@@ -49,7 +49,6 @@ export type ReactConsumer<T> = {
49
ref: null,
50
props: {
51
children: (value: T) => ReactNodeList,
52
- unstable_observedBits?: number,
52
...
53
},
54
...
@@ -59,7 +58,6 @@ export type ReactContext<T> = {
58
$$typeof: Symbol | number,
59
Consumer: ReactContext<T>,
60
Provider: ReactProviderType<T>,
62
- _calculateChangedBits: ((a: T, b: T) => number) | null,
61
_currentValue: T,
62
_currentValue2: T,
63
_threadCount: number,