Skip to content

Require Named Effect Functions

ErrorAuto-fixable
small-rules/require-named-effect-functions

Enforce named effect functions for better debuggability. Prevents inline arrow functions in useEffect and similar hooks.

Diagnostic Messages

anonymousFunction
Anonymous function passed to {{hook}}. debug.info returns empty string for anonymous functions, making stack traces useless for debugging. Extract to: function effectName() { ... } then pass effectName.
arrowFunction
Arrow function passed to {{hook}}. Arrow functions have no debug name and create new instances each render. Extract to: function effectName() { ... } then pass effectName.
asyncAnonymousFunction
Async anonymous function in {{hook}}. Two issues: (1) no debug name makes stack traces useless, (2) async effects require cancellation logic for unmount. Extract to: async function effectName() { ... } with cleanup.
asyncArrowFunction
Async arrow function in {{hook}}. Two issues: (1) arrow functions have no debug name, (2) async effects require cancellation logic. Extract to: async function effectName() { ... } with cleanup.
asyncFunctionDeclaration
Async function declaration passed to {{hook}}. Async effects require cancellation logic to handle component unmount. Implement cleanup or set allowAsync: true if cancellation is handled.
asyncFunctionExpression
Async function expression in {{hook}}. Async effects require cancellation logic for unmount. Extract to a named async function declaration with cleanup, then pass the reference.
functionExpression
Function expression passed to {{hook}}. Function expressions create new instances each render, breaking referential equality. Extract to: function effectName() { ... } at module or component top-level.
identifierReferencesArrow
{{hook}} receives identifier pointing to arrow function. Arrow functions have no debug name and lack referential stability. Convert to: function effectName() { ... } then pass effectName.
identifierReferencesAsyncArrow
{{hook}} receives identifier pointing to async arrow function. Two issues: (1) no debug name, (2) async effects require cancellation logic. Convert to: async function effectName() { ... } with cleanup.
identifierReferencesAsyncFunction
{{hook}} receives identifier pointing to async function. Async effects require cancellation logic for unmount. Implement cleanup or set allowAsync: true if cancellation is handled.
identifierReferencesCallback
{{hook}} receives identifier from useCallback/useMemo. These hooks return new references when dependencies change, causing unexpected effect re-runs. Use a stable function declaration: function effectName() { ... }
identifierReferencesFunctionDeclaration
{{hook}} receives identifier pointing to a named function declaration. Convert it to an inline named function expression so the effect callback is self-contained: useEffect(function effectName() {}, [])

Configuration

This rule accepts one options object after the severity.

environmentOptional

Environment mode: 'roblox-ts' only allows identifiers, 'standard' allows both identifiers and named function expressions

hooksOptional

Hook configuration objects with name and allowAsync settings.

inlineFunctionDeclarationsOptional

Convert effect callbacks that reference a named function declaration into inline named function expressions (standard and sloptor modes only), keeping the effect body visible to dependency analysis. When the declaration is only referenced by the effect and is not exported or commented, the fix also removes the now-unused declaration.

sloptorOptional

Compile with sloptor (a Go-based roblox-ts compiler). Sloptor targets @rbxts/react like roblox-ts but supports standard TypeScript features, so the rule applies standard-mode behavior. Use with environment: 'roblox-ts'.

{
"jsPlugins": [
"@pobammer-ts/small-rules"
],
"rules": {
"small-rules/require-named-effect-functions": [
"error",
{
"environment": "roblox-ts",
"hooks": [
{
"name": "useEffect",
"allowAsync": false
},
{
"name": "useLayoutEffect",
"allowAsync": false
},
{
"name": "useInsertionEffect",
"allowAsync": false
}
]
}
]
}
}

Examples

Anonymous effect callback
useEffect(() => {
print("effect");
}, []);
Named effect callback
function handleEffect() {
print("effect");
}
useEffect(handleEffect, []);