Skip to content

Commit 1a3b6b2

Browse files
committed
Remove isEqual argument
The isEqual argument mostly meant as a strawman. It has some known flaws: chiefly, if the isEqual function must always be in sync with the selector function; if isEqual changes, then isEqual is not valid for that render, because it'd be comparing the previous type with a new type. We have a few other ideas for how to solve the underlying problem, but in the meantime, let's remove it since we know it's not what we'll end up shipping.
1 parent 730d3a0 commit 1a3b6b2

File tree

6 files changed

+17
-130
lines changed

6 files changed

+17
-130
lines changed

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ function useContext<T>(
132132
function useSelectedContext<C, S>(
133133
Context: ReactContext<C>,
134134
selector: C => S,
135-
isEqual: ((S, S) => boolean) | void,
136135
): S {
137136
const context = Context._currentValue;
138137
const selection = selector(context);

packages/react-dom/src/server/ReactPartialRendererHooks.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,6 @@ function useContext<T>(
254254
function useSelectedContext<C, S>(
255255
Context: ReactContext<C>,
256256
selector: C => S,
257-
isEqual: ((S, S) => boolean) | void,
258257
): S {
259258
if (__DEV__) {
260259
currentHookNameInDev = 'useSelectedContext';

packages/react-reconciler/src/ReactFiberHooks.new.js

Lines changed: 15 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,6 @@ function updateWorkInProgressHook(): Hook {
638638
function mountSelectedContext<C, S>(
639639
Context: ReactContext<C>,
640640
selector: C => S,
641-
isEqual: ((S, S) => boolean) | void,
642641
): S {
643642
if (!enableContextSelectors) {
644643
return (undefined: any);
@@ -654,7 +653,6 @@ function mountSelectedContext<C, S>(
654653
function updateSelectedContext<C, S>(
655654
Context: ReactContext<C>,
656655
selector: C => S,
657-
isEqual: ((S, S) => boolean) | void,
658656
): S {
659657
if (!enableContextSelectors) {
660658
return (undefined: any);
@@ -664,20 +662,7 @@ function updateSelectedContext<C, S>(
664662
const context = readContextInsideHook(Context);
665663
const newSelection = selector(context);
666664
const oldSelection: S = hook.memoizedState;
667-
if (isEqual !== undefined) {
668-
if (__DEV__) {
669-
if (typeof isEqual !== 'function') {
670-
console.error(
671-
'The optional third argument to useSelectedContext must be a ' +
672-
'function. Instead got: %s',
673-
isEqual,
674-
);
675-
}
676-
}
677-
if (isEqual(newSelection, oldSelection)) {
678-
return oldSelection;
679-
}
680-
} else if (is(newSelection, oldSelection)) {
665+
if (is(newSelection, oldSelection)) {
681666
return oldSelection;
682667
}
683668
markWorkInProgressReceivedUpdate();
@@ -2267,17 +2252,13 @@ if (__DEV__) {
22672252
mountHookTypesDev();
22682253
return readContext(context, observedBits);
22692254
},
2270-
useSelectedContext<C, S>(
2271-
context: ReactContext<C>,
2272-
selector: C => S,
2273-
isEqual: ((S, S) => boolean) | void,
2274-
): S {
2255+
useSelectedContext<C, S>(context: ReactContext<C>, selector: C => S): S {
22752256
currentHookNameInDev = 'useSelectedContext';
22762257
mountHookTypesDev();
22772258
const prevDispatcher = ReactCurrentDispatcher.current;
22782259
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
22792260
try {
2280-
return mountSelectedContext(context, selector, isEqual);
2261+
return mountSelectedContext(context, selector);
22812262
} finally {
22822263
ReactCurrentDispatcher.current = prevDispatcher;
22832264
}
@@ -2416,17 +2397,13 @@ if (__DEV__) {
24162397
updateHookTypesDev();
24172398
return readContext(context, observedBits);
24182399
},
2419-
useSelectedContext<C, S>(
2420-
context: ReactContext<C>,
2421-
selector: C => S,
2422-
isEqual: ((S, S) => boolean) | void,
2423-
): S {
2400+
useSelectedContext<C, S>(context: ReactContext<C>, selector: C => S): S {
24242401
currentHookNameInDev = 'useSelectedContext';
24252402
updateHookTypesDev();
24262403
const prevDispatcher = ReactCurrentDispatcher.current;
24272404
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
24282405
try {
2429-
return mountSelectedContext(context, selector, isEqual);
2406+
return mountSelectedContext(context, selector);
24302407
} finally {
24312408
ReactCurrentDispatcher.current = prevDispatcher;
24322409
}
@@ -2561,17 +2538,13 @@ if (__DEV__) {
25612538
updateHookTypesDev();
25622539
return readContext(context, observedBits);
25632540
},
2564-
useSelectedContext<C, S>(
2565-
context: ReactContext<C>,
2566-
selector: C => S,
2567-
isEqual: ((S, S) => boolean) | void,
2568-
): S {
2541+
useSelectedContext<C, S>(context: ReactContext<C>, selector: C => S): S {
25692542
currentHookNameInDev = 'useSelectedContext';
25702543
updateHookTypesDev();
25712544
const prevDispatcher = ReactCurrentDispatcher.current;
25722545
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
25732546
try {
2574-
return updateSelectedContext(context, selector, isEqual);
2547+
return updateSelectedContext(context, selector);
25752548
} finally {
25762549
ReactCurrentDispatcher.current = prevDispatcher;
25772550
}
@@ -2707,17 +2680,13 @@ if (__DEV__) {
27072680
updateHookTypesDev();
27082681
return readContext(context, observedBits);
27092682
},
2710-
useSelectedContext<C, S>(
2711-
context: ReactContext<C>,
2712-
selector: C => S,
2713-
isEqual: ((S, S) => boolean) | void,
2714-
): S {
2683+
useSelectedContext<C, S>(context: ReactContext<C>, selector: C => S): S {
27152684
currentHookNameInDev = 'useSelectedContext';
27162685
updateHookTypesDev();
27172686
const prevDispatcher = ReactCurrentDispatcher.current;
27182687
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnRerenderInDEV;
27192688
try {
2720-
return updateSelectedContext(context, selector, isEqual);
2689+
return updateSelectedContext(context, selector);
27212690
} finally {
27222691
ReactCurrentDispatcher.current = prevDispatcher;
27232692
}
@@ -2855,18 +2824,14 @@ if (__DEV__) {
28552824
mountHookTypesDev();
28562825
return readContext(context, observedBits);
28572826
},
2858-
useSelectedContext<C, S>(
2859-
context: ReactContext<C>,
2860-
selector: C => S,
2861-
isEqual: ((S, S) => boolean) | void,
2862-
): S {
2827+
useSelectedContext<C, S>(context: ReactContext<C>, selector: C => S): S {
28632828
currentHookNameInDev = 'useSelectedContext';
28642829
warnInvalidHookAccess();
28652830
mountHookTypesDev();
28662831
const prevDispatcher = ReactCurrentDispatcher.current;
28672832
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnMountInDEV;
28682833
try {
2869-
return mountSelectedContext(context, selector, isEqual);
2834+
return mountSelectedContext(context, selector);
28702835
} finally {
28712836
ReactCurrentDispatcher.current = prevDispatcher;
28722837
}
@@ -3016,18 +2981,14 @@ if (__DEV__) {
30162981
updateHookTypesDev();
30172982
return readContext(context, observedBits);
30182983
},
3019-
useSelectedContext<C, S>(
3020-
context: ReactContext<C>,
3021-
selector: C => S,
3022-
isEqual: ((S, S) => boolean) | void,
3023-
): S {
2984+
useSelectedContext<C, S>(context: ReactContext<C>, selector: C => S): S {
30242985
currentHookNameInDev = 'useSelectedContext';
30252986
warnInvalidHookAccess();
30262987
updateHookTypesDev();
30272988
const prevDispatcher = ReactCurrentDispatcher.current;
30282989
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
30292990
try {
3030-
return updateSelectedContext(context, selector, isEqual);
2991+
return updateSelectedContext(context, selector);
30312992
} finally {
30322993
ReactCurrentDispatcher.current = prevDispatcher;
30332994
}
@@ -3178,18 +3139,14 @@ if (__DEV__) {
31783139
updateHookTypesDev();
31793140
return readContext(context, observedBits);
31803141
},
3181-
useSelectedContext<C, S>(
3182-
context: ReactContext<C>,
3183-
selector: C => S,
3184-
isEqual: ((S, S) => boolean) | void,
3185-
): S {
3142+
useSelectedContext<C, S>(context: ReactContext<C>, selector: C => S): S {
31863143
currentHookNameInDev = 'useSelectedContext';
31873144
warnInvalidHookAccess();
31883145
updateHookTypesDev();
31893146
const prevDispatcher = ReactCurrentDispatcher.current;
31903147
ReactCurrentDispatcher.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
31913148
try {
3192-
return updateSelectedContext(context, selector, isEqual);
3149+
return updateSelectedContext(context, selector);
31933150
} finally {
31943151
ReactCurrentDispatcher.current = prevDispatcher;
31953152
}

packages/react-reconciler/src/ReactInternalTypes.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -299,11 +299,7 @@ export type Dispatcher = {|
299299
context: ReactContext<T>,
300300
observedBits: void | number | boolean,
301301
): T,
302-
useSelectedContext<C, S>(
303-
context: ReactContext<C>,
304-
selector: (C) => S,
305-
isEqual: ((S, S) => boolean) | void,
306-
): S,
302+
useSelectedContext<C, S>(context: ReactContext<C>, selector: (C) => S): S,
307303
useRef<T>(initialValue: T): {|current: T|},
308304
useEffect(
309305
create: () => (() => void) | void,

packages/react-reconciler/src/__tests__/ReactContextSelectors-test.js

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -79,69 +79,6 @@ describe('ReactContextSelectors', () => {
7979
expect(root).toMatchRenderedOutput('A: 1, B: 1');
8080
});
8181

82-
// @gate experimental
83-
test('custom comparison function', async () => {
84-
const Context = React.createContext();
85-
86-
let setContext;
87-
function App() {
88-
const [context, _setContext] = useState({a: 0, b: 0, c: 0});
89-
setContext = _setContext;
90-
return (
91-
<Context.Provider value={context}>
92-
<Indirection />
93-
</Context.Provider>
94-
);
95-
}
96-
97-
// Intermediate parent that bails out. Children will only re-render when the
98-
// context changes.
99-
const Indirection = React.memo(() => {
100-
return <Child />;
101-
});
102-
103-
function Child() {
104-
const [a, b] = useSelectedContext(
105-
Context,
106-
// Select only the values we care about (a and b, but not c).
107-
context => [context.a, context.b],
108-
// Compare the selected values
109-
([a1, b1], [a2, b2]) => a1 === a2 && b1 === b2,
110-
);
111-
return <Text text={`A: ${a}, B: ${b}`} />;
112-
}
113-
114-
const root = ReactNoop.createRoot();
115-
await ReactNoop.act(async () => {
116-
root.render(<App />);
117-
});
118-
expect(Scheduler).toHaveYielded(['A: 0, B: 0']);
119-
expect(root).toMatchRenderedOutput('A: 0, B: 0');
120-
121-
// Update a. Should re-render, since it's part of the selection.
122-
await ReactNoop.act(async () => {
123-
setContext({a: 1, b: 0, c: 0});
124-
});
125-
expect(Scheduler).toHaveYielded(['A: 1, B: 0']);
126-
expect(root).toMatchRenderedOutput('A: 1, B: 0');
127-
128-
// Same with b.
129-
await ReactNoop.act(async () => {
130-
setContext({a: 1, b: 1, c: 0});
131-
});
132-
expect(Scheduler).toHaveYielded(['A: 1, B: 1']);
133-
expect(root).toMatchRenderedOutput('A: 1, B: 1');
134-
135-
// But not c. Should bail out, because it's not part of the selection.
136-
await ReactNoop.act(async () => {
137-
setContext({a: 1, b: 1, c: 1});
138-
});
139-
expect(Scheduler).toHaveYielded([
140-
// Child did not re-render
141-
]);
142-
expect(root).toMatchRenderedOutput('A: 1, B: 1');
143-
});
144-
14582
// @gate experimental
14683
test('useSelectedContext and useContext subscribing to same context in same component', async () => {
14784
const Context = React.createContext();

packages/react/src/ReactHooks.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ export function useContext<T>(
9191
export function useSelectedContext<C, S>(
9292
Context: ReactContext<C>,
9393
selector: C => S,
94-
isEqual: ((S, S) => boolean) | void,
9594
): S {
9695
const dispatcher = resolveDispatcher();
9796
if (__DEV__) {
@@ -113,7 +112,7 @@ export function useSelectedContext<C, S>(
113112
}
114113
}
115114
}
116-
return dispatcher.useSelectedContext(Context, selector, isEqual);
115+
return dispatcher.useSelectedContext(Context, selector);
117116
}
118117

119118
export function useState<S>(

0 commit comments

Comments
 (0)