Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -547,17 +547,6 @@ const allTests = {
// TODO: this should error but doesn't.
// errors: [functionError('use', 'notAComponent')],
},
{
code: normalizeIndent`
export default () => {
if (isVal) {
useState(0);
}
}
`,
// TODO: this should error but doesn't.
// errors: [genericError('useState')],
},
{
code: normalizeIndent`
function notAComponent() {
Expand Down Expand Up @@ -615,7 +604,7 @@ const allTests = {
onClick();
});
useServerEffect(() => {
onClick();
onClick();
});
}
`,
Expand Down Expand Up @@ -845,7 +834,7 @@ const allTests = {
},
{
code: normalizeIndent`
// Valid because functions created with useEffectEvent can be passed by reference in useLayoutEffect
// Valid because functions created with useEffectEvent can be passed by reference in useLayoutEffect
// and useInsertionEffect.
function MyComponent({ theme }) {
const onClick = useEffectEvent(() => {
Expand Down Expand Up @@ -915,6 +904,16 @@ const allTests = {
},
],
invalid: [
{
code: normalizeIndent`
export default () => {
if (isVal) {
useState(0);
}
}
`,
errors: [functionError('useState', 'default')],
},
{
syntax: 'flow',
code: normalizeIndent`
Expand Down
14 changes: 13 additions & 1 deletion packages/eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,9 +701,14 @@ const rule = {
context.report({node: hook, message});
} else if (codePathFunctionName) {
// Custom message if we found an invalid function name.
// Handle both real AST nodes and synthetic identifiers (e.g., for default exports)
const functionNameText =
'name' in codePathFunctionName && typeof codePathFunctionName.name === 'string'
? codePathFunctionName.name
: getSourceCode().getText(codePathFunctionName);
const message =
`React Hook "${getSourceCode().getText(hook)}" is called in ` +
`function "${getSourceCode().getText(codePathFunctionName)}" ` +
`function "${functionNameText}" ` +
'that is neither a React function component nor a custom ' +
'React Hook function.' +
' React component names must start with an uppercase letter.' +
Expand Down Expand Up @@ -916,6 +921,13 @@ function getFunctionName(node: Node) {
// Kinda clowny, but we'd said we'd follow spec convention for
// `IsAnonymousFunctionDefinition()` usage.
return node.parent.left;
} else if (node.parent?.type === 'ExportDefaultDeclaration') {
// export default () => {};
// export default function() {};
//
// For default exports, we use a synthetic identifier to represent
// the "default" export name, which is not a valid component name.
return {type: 'Identifier', name: 'default'} as Node;
} else {
return undefined;
}
Expand Down