Skip to content

fix(compiler): recognize 'use' as a hook for hook detection#704

Open
everettbu wants to merge 1 commit intomainfrom
fix/use-hook-recognition
Open

fix(compiler): recognize 'use' as a hook for hook detection#704
everettbu wants to merge 1 commit intomainfrom
fix/use-hook-recognition

Conversation

@everettbu
Copy link
Copy Markdown

Mirror of facebook/react#36028
Original author: MorikawaSouma


Summary

React's \use()\ API is a hook for reading context and promises, but the compiler's \isHookName()\ function only matched the \use[A-Z0-9]\ pattern, causing custom hooks that only call \use()\ to be silently skipped during compilation.

Problem

When a custom hook only contains a \use()\ call:

\\js
function useMyContext() {
return use(MyContext);
}
\\

The compiler would skip this function because \use\ does not match /^use[A-Z0-9]/. This resulted in no memoization being applied.

Solution

Add 'use'\ to the hook name recognition in \isHookName()\ so that \use()\ is correctly identified as a hook call.

Test Plan

Verified by checking that:

  1. \isHookName('use')\ now returns \ rue\
  2. \isHookName('useContext'), \isHookName('useState')\ still work correctly
  3. Functions calling only \use()\ will now be compiled with memoization

Fixes #35960

React's 'use()' API is a hook for reading context and promises,
but the compiler's isHookName() function only matched 'use[A-Z0-9]'
pattern, causing custom hooks that only call use() to be silently
skipped during compilation.

This fix adds 'use' to the hook name recognition so that functions
like:
  function useMyContext() {
    return use(MyContext);
  }
will now be correctly compiled with memoization.

Fixes #35960
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Mar 13, 2026

Greptile Summary

This PR mirrors facebook/react#36028 and fixes a bug where custom hooks that only call React's use() API were silently skipped by the compiler because 'use' did not match the /^use[A-Z0-9]/ pattern. The fix in Program.ts is correct for its scope — it makes callsHooksOrCreatesJsx recognize a use() call-site as a hook invocation, and getComponentOrHookLike recognize a function literally named use as a hook, matching the already-updated eslint-plugin-react-hooks implementation.

However, there is a material inconsistency left behind:

  • Environment.ts's exported isHookName (line 1037) was not updated. This is the function imported by ValidateHooksUsage.ts, Globals.ts, and Imports.ts for hook detection inside the HIR pipeline. As described in the comment on Program.ts, this could cause incorrect errors for user-configured type providers that expose a function named 'use' as a hook, and could cause the compiler to under-type third-party use-named imports.
  • scripts/babel-plugin-annotate-react-code.ts (line 139) also has a local isHookName with the old pattern, potentially causing annotation misses for functions that only call use().
  • No test fixtures were added. The test plan in the PR description is manual; no automated snapshot tests covering the described scenario (a custom hook that only calls use()) were included.

Confidence Score: 3/5

  • The core fix is correct but incomplete — the companion isHookName in Environment.ts used by the HIR pipeline was not updated, leaving the compiler internally inconsistent.
  • The change in Program.ts is correct and addresses the entry-point detection problem. However, the exported isHookName in Environment.ts — which is what the HIR compilation passes actually use — was not updated. This means hook-usage validation (ValidateHooksUsage.ts), type resolution for non-React use-named imports, and user-configured type providers can still behave incorrectly for 'use'. No test fixtures were added to verify the fix or guard against regressions.
  • compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts (line 1037) needs the same name === 'use' || update; compiler/packages/babel-plugin-react-compiler/scripts/babel-plugin-annotate-react-code.ts (line 139) may also need updating.

Important Files Changed

Filename Overview
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts Adds s === 'use' to the local isHookName function so that functions calling React's use() API are recognized as hooks during entry-point detection. The fix is logically correct for its scope, but Environment.ts exports a separate isHookName with an identical comment that was NOT updated, creating an inconsistency in the compiler's HIR pipeline.

Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
Line: 898

Comment:
**Sibling `isHookName` in `Environment.ts` not updated**

There is a second, independently-defined `isHookName` exported from `compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts` (line 1037) that still uses only the old regex:

```ts
// Environment.ts – unchanged
export function isHookName(name: string): boolean {
  return /^use[A-Z0-9]/.test(name);
}
```

This exported function is the one actually used throughout the HIR pipeline – `ValidateHooksUsage.ts`, `Globals.ts`, and `Imports.ts` all import it. Because it was not updated, identifiers named exactly `'use'` are not treated as hook names inside compilation:

1. **`Globals.ts` (line 1027)** — When a user-supplied type provider configures a function called `'use'` as a hook, `isHookName('use')` returns `false` but the type check returns `true`, triggering a spurious `CompilerError.throwInvalidConfig`.
2. **`Environment.ts` (line 858 / 897)** — For non-React third-party imports whose name is `'use'`, the fallback `isHookName` check will not assign the custom hook type.
3. **`ValidateHooksUsage.ts` (lines 168, 197)** — Hook-usage validation based on identifier names will miss identifiers named `'use'`.

The comment on `Environment.ts`'s `isHookName` explicitly says it mirrors the eslint-plugin-react-hooks implementation, and that source (`eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts` line 30) has *already* been updated to `s === 'use' || /^use[A-Z0-9]/.test(s)`. The same update should be applied here:

```ts
// Environment.ts
export function isHookName(name: string): boolean {
  return name === 'use' || /^use[A-Z0-9]/.test(name);
}
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 7af1c89


function isHookName(s: string): boolean {
return /^use[A-Z0-9]/.test(s);
return s === 'use' || /^use[A-Z0-9]/.test(s);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sibling isHookName in Environment.ts not updated

There is a second, independently-defined isHookName exported from compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts (line 1037) that still uses only the old regex:

// Environment.ts – unchanged
export function isHookName(name: string): boolean {
  return /^use[A-Z0-9]/.test(name);
}

This exported function is the one actually used throughout the HIR pipeline – ValidateHooksUsage.ts, Globals.ts, and Imports.ts all import it. Because it was not updated, identifiers named exactly 'use' are not treated as hook names inside compilation:

  1. Globals.ts (line 1027) — When a user-supplied type provider configures a function called 'use' as a hook, isHookName('use') returns false but the type check returns true, triggering a spurious CompilerError.throwInvalidConfig.
  2. Environment.ts (line 858 / 897) — For non-React third-party imports whose name is 'use', the fallback isHookName check will not assign the custom hook type.
  3. ValidateHooksUsage.ts (lines 168, 197) — Hook-usage validation based on identifier names will miss identifiers named 'use'.

The comment on Environment.ts's isHookName explicitly says it mirrors the eslint-plugin-react-hooks implementation, and that source (eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts line 30) has already been updated to s === 'use' || /^use[A-Z0-9]/.test(s). The same update should be applied here:

// Environment.ts
export function isHookName(name: string): boolean {
  return name === 'use' || /^use[A-Z0-9]/.test(name);
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
Line: 898

Comment:
**Sibling `isHookName` in `Environment.ts` not updated**

There is a second, independently-defined `isHookName` exported from `compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts` (line 1037) that still uses only the old regex:

```ts
// Environment.ts – unchanged
export function isHookName(name: string): boolean {
  return /^use[A-Z0-9]/.test(name);
}
```

This exported function is the one actually used throughout the HIR pipeline – `ValidateHooksUsage.ts`, `Globals.ts`, and `Imports.ts` all import it. Because it was not updated, identifiers named exactly `'use'` are not treated as hook names inside compilation:

1. **`Globals.ts` (line 1027)** — When a user-supplied type provider configures a function called `'use'` as a hook, `isHookName('use')` returns `false` but the type check returns `true`, triggering a spurious `CompilerError.throwInvalidConfig`.
2. **`Environment.ts` (line 858 / 897)** — For non-React third-party imports whose name is `'use'`, the fallback `isHookName` check will not assign the custom hook type.
3. **`ValidateHooksUsage.ts` (lines 168, 197)** — Hook-usage validation based on identifier names will miss identifiers named `'use'`.

The comment on `Environment.ts`'s `isHookName` explicitly says it mirrors the eslint-plugin-react-hooks implementation, and that source (`eslint-plugin-react-hooks/src/rules/RulesOfHooks.ts` line 30) has *already* been updated to `s === 'use' || /^use[A-Z0-9]/.test(s)`. The same update should be applied here:

```ts
// Environment.ts
export function isHookName(name: string): boolean {
  return name === 'use' || /^use[A-Z0-9]/.test(name);
}
```

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants