Skip to content

[compiler] Fix use hook resolution for aliased React imports#36149

Open
cyphercodes wants to merge 1 commit intofacebook:mainfrom
cyphercodes:main
Open

[compiler] Fix use hook resolution for aliased React imports#36149
cyphercodes wants to merge 1 commit intofacebook:mainfrom
cyphercodes:main

Conversation

@cyphercodes
Copy link
Copy Markdown

Summary

When importing React with an alias (e.g., import ReactAlias from 'react'), the compiler was not correctly resolving the 'use' hook type. This caused the compiled output to place the hook call inside a conditional cache block, violating the Rules of Hooks.

Problem

The issue was in the Environment.ts file where imports from known React modules are resolved. When a user imports React with a different name like:

The compiler looked up ReactAlias in the globals map, but the React object type is stored under the key 'React'. This meant that when the compiler encountered ReactAlias.use(), it didn't recognize use as the special built-in use operator.

Solution

The fix ensures that default imports from 'react' always resolve to the React global type, regardless of the local binding name.

Test Plan

Added a test fixture that verifies the correct behavior when using ReactAlias.use().

Fixes #36137

When importing React with an alias (e.g., import ReactAlias from 'react'),
the compiler was not correctly resolving the 'use' hook type. This caused
the compiled output to place the hook call inside a conditional cache block,
violating the Rules of Hooks.

The fix ensures that default imports from 'react' always resolve to the
React global type, regardless of the local binding name.

Fixes facebook#36137
@meta-cla meta-cla bot added the CLA Signed label Mar 26, 2026
Copy link
Copy Markdown

@mahdirajaee mahdirajaee left a comment

Choose a reason for hiding this comment

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

Good catch. The core issue is clear: when someone writes import ReactAlias from 'react' and then calls ReactAlias.use(), the compiler was trying to look up the global type using ReactAlias as the key (which doesn't exist in the globals map) instead of resolving it to the canonical React global.

The fix is targeted and makes sense:

  1. The condition is specific enoughbinding.kind === 'ImportDefault' && binding.module.toLowerCase() === 'react' ensures this only applies to default imports from the react module. Named imports and namespace imports continue through the existing path, which is correct since import { useState } from 'react' would already resolve useState by name.

  2. The .toLowerCase() on the module check — is this intentional? In practice, 'react' should always be lowercase in the import specifier, but if there's a case-insensitive filesystem edge case being handled here, a comment explaining that would be helpful.

  3. Edge case consideration — what about import ReactAlias from 'react' followed by ReactAlias.useState()? Based on the fix, ReactAlias would resolve to the React global type, so member access like .useState() should work correctly since the global React type already has those members defined. The test fixture only covers .use() though — it might be worth adding a fixture for other hooks accessed through an alias to confirm.

  4. What about re-exports? — e.g., a local module that does export { default } from 'react' and then import R from './myReactReexport'. This wouldn't be caught since binding.module wouldn't be 'react', but that's a separate (and much harder) problem.

  5. The test fixture is cleanuse-hook-aliased-import.js demonstrates the exact scenario, and the expected output shows the compiler correctly memoizing the result.

Looks good overall. The fix is narrowly scoped to the actual problem without overreaching.

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.

[Compiler Bug]: incorrectly handles use hook when called on a non-React object

2 participants