Remove custom error message from hook access error (#20604)
It will still result in a null access error, so there's no change in semantics. We will print a user-friendly error message in DEV.
Andrew Clark committed
Jan 19, 2021 at 16:20 UTC
58e8304483ebfadd02a295339b5e9a989ac98c6e
3 files changed
+28
-15
packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js
+5
-2
@@ -277,14 +277,17 @@ describe('ReactHooksInspection', () => {
277
};
278
279
expect(() => {
280
- ReactDebugTools.inspectHooks(Foo, {}, FakeDispatcherRef);
281
- }).toThrow(
280
+ expect(() => {
281
+ ReactDebugTools.inspectHooks(Foo, {}, FakeDispatcherRef);
282
+ }).toThrow("Cannot read property 'useState' of null");
283
+ }).toErrorDev(
284
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
285
' one of the following reasons:\n' +
286
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
287
'2. You might be breaking the Rules of Hooks\n' +
288
'3. You might have more than one copy of React in the same app\n' +
289
'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.',
290
+ {withoutStack: true},
291
);
292
293
expect(getterCalls).toBe(1);
packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js
+6
-1
@@ -249,13 +249,18 @@ describe('ReactHooksWithNoopRenderer', () => {
249
}
250
251
it('throws when called outside the render phase', () => {
252
- expect(() => useState(0)).toThrow(
252
+ expect(() => {
253
+ expect(() => useState(0)).toThrow(
254
+ "Cannot read property 'useState' of null",
255
+ );
256
+ }).toErrorDev(
257
'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
258
' one of the following reasons:\n' +
259
'1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
260
'2. You might be breaking the Rules of Hooks\n' +
261
'3. You might have more than one copy of React in the same app\n' +
262
'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.',
263
+ {withoutStack: true},
264
);
265
});
266
packages/react/src/ReactHooks.js
+17
-12
@@ -7,6 +7,7 @@
7
* @flow
8
*/
9
10
+import type {Dispatcher} from 'react-reconciler/src/ReactInternalTypes';
11
import type {
12
MutableSource,
13
MutableSourceGetSnapshotFn,
@@ -15,8 +16,6 @@ import type {
16
} from 'shared/ReactTypes';
17
import type {OpaqueIDType} from 'react-reconciler/src/ReactFiberHostConfig';
18
18
-import invariant from 'shared/invariant';
19
-
19
import ReactCurrentDispatcher from './ReactCurrentDispatcher';
20
21
type BasicStateAction<S> = (S => S) | S;
@@ -24,16 +23,22 @@ type Dispatch<A> = A => void;
23
24
function resolveDispatcher() {
25
const dispatcher = ReactCurrentDispatcher.current;
27
- invariant(
28
- dispatcher !== null,
29
- 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
30
- ' one of the following reasons:\n' +
31
- '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
32
- '2. You might be breaking the Rules of Hooks\n' +
33
- '3. You might have more than one copy of React in the same app\n' +
34
- 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.',
35
- );
36
- return dispatcher;
26
+ if (__DEV__) {
27
+ if (dispatcher === null) {
28
+ console.error(
29
+ 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' +
30
+ ' one of the following reasons:\n' +
31
+ '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' +
32
+ '2. You might be breaking the Rules of Hooks\n' +
33
+ '3. You might have more than one copy of React in the same app\n' +
34
+ 'See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.',
35
+ );
36
+ }
37
+ }
38
+ // Will result in a null access error if accessed outside render phase. We
39
+ // intentionally don't throw our own error because this is in a hot path.
40
+ // Also helps ensure this is inlined.
41
+ return ((dispatcher: any): Dispatcher);
42
}
43
44
export function getCacheForType<T>(resourceType: () => T): T {