From fb572afc14ec5d25aea9be5d752007cc3b2e362f Mon Sep 17 00:00:00 2001 From: Jared Palmer Date: Mon, 18 Mar 2019 14:22:38 -0400 Subject: [PATCH] Add more info to invalid hook call error message (#15139) * Add more info to invalid hook call error message * Update other renderers + change call to action * Update related tests for new hooks error message * Fix lint errors --- .../__tests__/ReactHooksInspection-test.js | 7 ++++- .../ReactHooksInspectionIntegration-test.js | 7 ++++- ...DOMServerIntegrationHooks-test.internal.js | 14 ++++++++-- .../src/server/ReactPartialRendererHooks.js | 8 ++++-- .../react-reconciler/src/ReactFiberHooks.js | 8 ++++-- .../src/__tests__/ReactHooks-test.internal.js | 28 ++++++++++++++++--- ...eactHooksWithNoopRenderer-test.internal.js | 21 ++++++++++++-- .../ReactNewContext-test.internal.js | 7 ++++- .../src/ReactShallowRenderer.js | 8 ++++-- packages/react/src/ReactHooks.js | 8 ++++-- 10 files changed, 96 insertions(+), 20 deletions(-) diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js index b340779a74d1..32f77ddc6470 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspection-test.js @@ -239,7 +239,12 @@ describe('ReactHooksInspection', () => { expect(() => { ReactDebugTools.inspectHooks(Foo, {}, FakeDispatcherRef); }).toThrow( - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); expect(getterCalls).toBe(1); diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index 8c56c8cd775a..23c5a1883287 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -419,7 +419,12 @@ describe('ReactHooksInspectionIntegration', () => { expect(() => { ReactDebugTools.inspectHooksOfFiber(childFiber, FakeDispatcherRef); }).toThrow( - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); expect(getterCalls).toBe(1); diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js index 3ad64377e813..f48e5780256e 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js @@ -144,7 +144,12 @@ describe('ReactDOMServerHooks', () => { return render(); }, - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); itRenders('multiple times when an updater is called', async render => { @@ -626,7 +631,12 @@ describe('ReactDOMServerHooks', () => { return render(); }, - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); }); diff --git a/packages/react-dom/src/server/ReactPartialRendererHooks.js b/packages/react-dom/src/server/ReactPartialRendererHooks.js index d568d002e78a..00c786988355 100644 --- a/packages/react-dom/src/server/ReactPartialRendererHooks.js +++ b/packages/react-dom/src/server/ReactPartialRendererHooks.js @@ -57,8 +57,12 @@ let currentHookNameInDev: ?string; function resolveCurrentlyRenderingComponent(): Object { invariant( currentlyRenderingComponent !== null, - 'Hooks can only be called inside the body of a function component. ' + - '(https://fb.me/react-invalid-hook-call)', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); if (__DEV__) { warning( diff --git a/packages/react-reconciler/src/ReactFiberHooks.js b/packages/react-reconciler/src/ReactFiberHooks.js index 00e2e29c8037..baa07a4c59b5 100644 --- a/packages/react-reconciler/src/ReactFiberHooks.js +++ b/packages/react-reconciler/src/ReactFiberHooks.js @@ -262,8 +262,12 @@ function warnOnHookMismatchInDev(currentHookName: HookType) { function throwInvalidHookError() { invariant( false, - 'Hooks can only be called inside the body of a function component. ' + - '(https://fb.me/react-invalid-hook-call)', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); } diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js index a9313f2fd547..58d74bf6d0b1 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js @@ -44,7 +44,12 @@ describe('ReactHooks', () => { expect(() => { ReactTestRenderer.create(); }).toThrow( - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen' + + ' for one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); }); } @@ -805,15 +810,30 @@ describe('ReactHooks', () => { const root = ReactTestRenderer.create(); // trying to render again should trigger comparison and throw expect(() => root.update()).toThrow( - 'Hooks can only be called inside the body of a function component', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); // the next round, it does a fresh mount, so should render expect(() => root.update()).not.toThrow( - 'Hooks can only be called inside the body of a function component', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); // and then again, fail expect(() => root.update()).toThrow( - 'Hooks can only be called inside the body of a function component', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); }); diff --git a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js index 4c4da75af7ca..192c077c1c79 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.internal.js @@ -108,7 +108,12 @@ describe('ReactHooksWithNoopRenderer', () => { ReactNoop.render(); expect(() => ReactNoop.flush()).toThrow( - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); // Confirm that a subsequent hook works properly. @@ -131,7 +136,12 @@ describe('ReactHooksWithNoopRenderer', () => { } ReactNoop.render(); expect(() => ReactNoop.flush()).toThrow( - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); // Confirm that a subsequent hook works properly. @@ -145,7 +155,12 @@ describe('ReactHooksWithNoopRenderer', () => { it('throws when called outside the render phase', () => { expect(() => useState(0)).toThrow( - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); }); diff --git a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js index 38de5af0fbd4..b118bdcedfc6 100644 --- a/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactNewContext-test.internal.js @@ -1514,7 +1514,12 @@ describe('ReactNewContext', () => { } ReactNoop.render(); expect(ReactNoop.flush).toThrow( - 'Hooks can only be called inside the body of a function component.', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen' + + ' for one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); }); diff --git a/packages/react-test-renderer/src/ReactShallowRenderer.js b/packages/react-test-renderer/src/ReactShallowRenderer.js index 120fe54383ea..850b2b37417b 100644 --- a/packages/react-test-renderer/src/ReactShallowRenderer.js +++ b/packages/react-test-renderer/src/ReactShallowRenderer.js @@ -218,8 +218,12 @@ class ReactShallowRenderer { _validateCurrentlyRenderingComponent() { invariant( this._rendering && !this._instance, - 'Hooks can only be called inside the body of a function component. ' + - '(https://fb.me/react-invalid-hook-call)', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); } diff --git a/packages/react/src/ReactHooks.js b/packages/react/src/ReactHooks.js index 271acb4bede9..8e7ebe19e731 100644 --- a/packages/react/src/ReactHooks.js +++ b/packages/react/src/ReactHooks.js @@ -17,8 +17,12 @@ function resolveDispatcher() { const dispatcher = ReactCurrentDispatcher.current; invariant( dispatcher !== null, - 'Hooks can only be called inside the body of a function component. ' + - '(https://fb.me/react-invalid-hook-call)', + 'Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for' + + ' one of the following reasons:\n' + + '1. You might have mismatching versions of React and the renderer (such as React DOM)\n' + + '2. You might be breaking the Rules of Hooks\n' + + '3. You might have more than one copy of React in the same app\n' + + 'See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.', ); return dispatcher; }