diff --git a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js index 0c782dc25ae02..2a2786dca8850 100644 --- a/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js +++ b/packages/eslint-plugin-react-hooks/__tests__/ESLintRuleExhaustiveDeps-test.js @@ -1692,6 +1692,42 @@ const tests = { }, ], }, + { + code: normalizeIndent` + function MyComponent() { + useEffect() + useLayoutEffect() + useCallback() + useMemo() + } + `, + errors: [ + { + message: + 'React Hook useEffect requires an effect callback. ' + + 'Did you forget to pass a callback to the hook?', + suggestions: undefined, + }, + { + message: + 'React Hook useLayoutEffect requires an effect callback. ' + + 'Did you forget to pass a callback to the hook?', + suggestions: undefined, + }, + { + message: + 'React Hook useCallback requires an effect callback. ' + + 'Did you forget to pass a callback to the hook?', + suggestions: undefined, + }, + { + message: + 'React Hook useMemo requires an effect callback. ' + + 'Did you forget to pass a callback to the hook?', + suggestions: undefined, + }, + ], + }, { // Regression test code: normalizeIndent` diff --git a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js index 7c970f7c8f6ac..ee259b2d37cd6 100644 --- a/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js +++ b/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js @@ -1119,6 +1119,19 @@ export default { const declaredDependenciesNode = node.arguments[callbackIndex + 1]; const isEffect = /Effect($|[^a-z])/g.test(reactiveHookName); + // Check whether a callback is supplied. If there is no callback supplied + // then the hook will not work and React will throw a TypeError. + // So no need to check for dependency inclusion. + if (!callback) { + reportProblem({ + node: reactiveHook, + message: + `React Hook ${reactiveHookName} requires an effect callback. ` + + `Did you forget to pass a callback to the hook?`, + }); + return; + } + // Check the declared dependencies for this reactive hook. If there is no // second argument then the reactive callback will re-run on every render. // So no need to check for dependency inclusion.