Skip to content

[Tracking] Use React Compiler to enforce the Rules of React #68765

Closed
3 of 3 issues completed
Closed

Description

@roryabraham

Coming from https://expensify.slack.com/archives/C08CZDJFJ77/p1754356010769039

Background: The React Compiler is meant to automatically optimize React code with invisible React.memo, useMemo, and useCallback calls. This in theory eliminates the need to use these React constructs in the codebase.

However, we see many examples where performance can be improved with useMemo. It's unclear when React Compiler will "do it's thing" and when it won't.

Furthermore, we have many many components and hooks throughout the codebase the violate the Rules of React.

The React Compiler has come a long way since this issue was first created, and it's now much more tightly integrated with lint rules in eslint-plugin-react-hooks which are designed precisely to help enforce the Rules of React and to teach developers how to write better React Code in the process.

Problem:

  1. (done) Update eslint-plugin-react-hooks and enable all rules globally. See what errors crop up. There were 559.
  2. (done) Make them all warnings in the global ESLint config, and set --max-warnings accordingly so that npm run lint passes on main.
  3. Create issues to fix all the react-hooks lint rules, work through them in batches. At the end of this effort:
    • All files should be compiled with React Compiler
    • All files should be compliant with the Rules of React (insofar as the React Compiler can currently enforce that)
  4. (optional) Create issues to start removing all unnecessary manual memoization (to simplify/reduce the codebase, and potentially see performance gains)

Activity

  1. roryabraham commented on Aug 19, 2025

    @roryabraham
    ContributorAuthor

    Similar PR check was added in the past: #49397

  2. roryabraham commented on Aug 26, 2025

    @roryabraham
    ContributorAuthor

    any update @chrispader

  3. moved this from HIGH to MEDIUM in [#whatsnext] #qualityon Aug 26, 2025
  4. roryabraham commented on Aug 26, 2025

    @roryabraham
    ContributorAuthor

    @mountiny moved this to MEDIUM, as that feels more appropriate than HIGH to me for this particular issue

  5. mountiny commented on Aug 28, 2025

    @mountiny
    Contributor

    Cool, I'm fine with that. Thanks for the ping!

  6. roryabraham commented on Sep 3, 2025

    @roryabraham
    ContributorAuthor

    @chrispader any update here?

  7. chrispader commented on Sep 8, 2025

    @chrispader
    Contributor

    hey @roryabraham sorry for the late update, i was busy with other PRs. I wasn't able to work on this yet, but i'd like to start either today or tomorrow. Lmk if this needs to be handled more urgently, maybe i can get someone from Margelo to work on it!

  8. roryabraham commented on Sep 9, 2025

    @roryabraham
    ContributorAuthor

    No worries @chrispader. Do you think you can get a PR up this week?

  9. chrispader commented on Sep 10, 2025

    @chrispader
    Contributor

    yes, i'll have a PR up by the end of tomorrow!

  10. 347 remaining items

  11. roryabraham commented on Oct 20, 2026

    @roryabraham
    ContributorAuthor

    @MelvinBot how many components and hooks do we have total, and how many do not compile with React Compiler? Focus only on the Rust React Compiler now, since soon that will be the only one we have

  12. MelvinBot commented on Oct 20, 2026

    @MelvinBot
    Contributor

    We have 4,895 components and hooks. 85 of them (1.7%) do not compile with the OXC (Rust) React Compiler.

    Total Don't compile
    Components 3,740 66
    Hooks 1,155 19
    Total 4,895 85

    Why they fail (first OXC error for each function):

    • 64: Cannot access refs during render
    • 8: Existing memoization could not be preserved
    • 4: This value cannot be modified
    • 7: Compiler limitations (getters in object literals, try/finally, ??=, dynamic import(), and others)
    • 2: Internal compiler invariant errors (usePermissions, web useSingleExecution)

    Note: react-compiler-compliance-check flags only 71 of these files. It runs OXC with panicThreshold: 'critical_errors', so memoization-preservation and limitation bailouts pass the check. The web build still ships those 14 functions uncompiled.

    How I counted
    • Scope: every .ts/.tsx/.js file under src/, excluding tests/ (8,118 files), at App 6eb1f75. Platform variants (.native.tsx, .web.tsx) count as separate functions. A "hook" is a function whose name starts with use.
    • Inventory: the functions React Compiler treats as components or hooks in infer mode. I took them from the babel-plugin-react-compiler logger (CompileSuccess and CompileError events). OXC did not compile any function outside this inventory, so both compilers agree on the set.
    • OXC result: oxc-transform-react 0.148.0 with the production web config (oxcReactCompilerConfig.js, panicThreshold: 'none'), plus the gating option. Gating wraps every function OXC compiles in gate() ? compiled : original, so counting the wrappers gives an exact per-function result. In every file, the memo-cache count matched the ungated build.
    • Reasons: for each failing function, I re-ran OXC with panicThreshold: 'all_errors' and recorded the first diagnostic.
    • No function uses "use no memo". All 85 OXC failures also fail under Babel.
    All 85 components and hooks that don't compile
    Name Kind First OXC error
    Expensify Expensify.tsx Component Cannot access refs during render
    GlobalModals GlobalModals.tsx Component Cannot access refs during render
    AnimatedSubmitButton components/AnimatedSubmitButton/index.tsx Component Cannot access refs during render
    AttachmentPicker components/AttachmentPicker/index.native.tsx Component Cannot access refs during render
    AttachmentPicker components/AttachmentPicker/index.tsx Component Cannot access refs during render
    AttachmentCarouselView components/Attachments/AttachmentCarousel/AttachmentCarouselView/index.tsx Component Cannot access refs during render
    TransparentOverlay components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/TransparentOverlay/TransparentOverlay.tsx Component Cannot access refs during render
    Composer components/Composer/implementation/index.native.tsx Component Existing memoization could not be preserved
    Composer components/Composer/implementation/index.tsx Component Limitation: Handle get functions in ObjectExpression
    ConnectToNetSuiteFlow components/ConnectToNetSuiteFlow/index.tsx Component Cannot access refs during render
    DatePicker components/DatePicker/index.tsx Component Cannot access refs during render
    DisplayNamesWithToolTip components/DisplayNames/DisplayNamesWithTooltip.tsx Component Cannot access refs during render
    NoDropZone components/DragAndDrop/NoDropZone/index.tsx Component Cannot access refs during render
    DragAndDropProvider components/DragAndDrop/Provider/index.tsx Component Cannot access refs during render
    DropZoneWrapper components/DropZone/DropZoneWrapper.tsx Component Cannot access refs during render
    EmojiPicker components/EmojiPicker/EmojiPicker.tsx Component Cannot access refs during render
    EmojiPickerMenu components/EmojiPicker/EmojiPickerMenu/index.native.tsx Component Cannot access refs during render
    EmojiPickerMenu components/EmojiPicker/EmojiPickerMenu/index.tsx Component Cannot access refs during render
    FilePicker components/FilePicker/index.native.tsx Component Cannot access refs during render
    FilePicker components/FilePicker/index.tsx Component Cannot access refs during render
    FormProvider components/Form/FormProvider.tsx Component This value cannot be modified
    InputWrapper components/Form/InputWrapper.tsx Component Cannot access refs during render
    ActiveHoverable components/Hoverable/ActiveHoverable.tsx Component Cannot access refs during render
    Hoverable components/Hoverable/index.tsx Component Cannot access refs during render
    Image components/Image/index.tsx Component Cannot access refs during render
    ImportSpreadsheet components/ImportSpreadsheet.tsx Component Limitation: Handle Import expressions
    KYCWall components/KYCWall/BaseKYCWall.tsx Component Cannot access refs during render
    Container components/Modal/ReanimatedModal/Container/index.web.tsx Component Cannot access refs during render
    MoneyRequestAmountInput components/MoneyRequestAmountInput.tsx Component This value cannot be modified
    MultiGestureCanvas components/MultiGestureCanvas/index.tsx Component Cannot access refs during render
    GenericPressable components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx Component Cannot access refs during render
    AddReactionBubble components/Reactions/AddReactionBubble.tsx Component Cannot access refs during render
    MiniQuickEmojiReactions components/Reactions/MiniQuickEmojiReactions.tsx Component Cannot access refs during render
    ExportWithDropdownMenu components/ReportActionItem/ExportWithDropdownMenu.tsx Component Existing memoization could not be preserved
    ScreenWrapperContainer components/ScreenWrapper/ScreenWrapperContainer.tsx Component Cannot access refs during render
    Search components/Search/index.tsx Component Cannot access refs during render
    SwipeableView components/SwipeableView/index.native.tsx Component Cannot access refs during render
    BaseTextInput components/TextInput/BaseTextInput/implementation/index.native.tsx Component Cannot access refs during render
    BaseTextInput components/TextInput/BaseTextInput/implementation/index.tsx Component Cannot access refs during render
    BaseGenericTooltip components/Tooltip/BaseGenericTooltip/index.native.tsx Component Cannot access refs during render
    BaseGenericTooltip components/Tooltip/BaseGenericTooltip/index.tsx Component This value cannot be modified
    PopoverAnchorTooltip components/Tooltip/PopoverAnchorTooltip.tsx Component Cannot access refs during render
    BaseVideoPlayer components/VideoPlayer/BaseVideoPlayer.tsx Component Cannot access refs during render
    CurrentReportIDContextProvider hooks/useCurrentReportID.tsx Component Existing memoization could not be preserved
    SidebarOrderedReportsContextProvider hooks/useSidebarOrderedReports.tsx Component Cannot access refs during render
    AuthScreensInitHandler libs/Navigation/AppNavigator/AuthScreensInitHandler.tsx Component Cannot access refs during render
    DelegatorConnectGate libs/Navigation/AppNavigator/DelegatorConnectGate.tsx Component Logical assignment operators (||=, &&=, ??=) are not yet supported
    AddressStep pages/MissingPersonalDetails/subPages/Address.tsx Component Cannot access refs during render
    ReimbursementAccountPage pages/ReimbursementAccount/ReimbursementAccountPage.tsx Component Cannot access refs during render
    DynamicConfirmationPage pages/TransactionDuplicate/DynamicConfirmationPage.tsx Component Cannot access refs during render
    BaseReportActionContextMenu pages/inbox/report/ContextMenu/BaseReportActionContextMenu.tsx Component Cannot access refs during render
    PopoverReportActionContextMenu pages/inbox/report/ContextMenu/PopoverReportActionContextMenu.tsx Component Cannot access refs during render
    ComposerWithSuggestions pages/inbox/report/ReportActionCompose/ComposerWithSuggestions.tsx Component Cannot access refs during render
    SuggestionEmoji pages/inbox/report/ReportActionCompose/SuggestionEmoji.tsx Component Cannot access refs during render
    SuggestionMention pages/inbox/report/ReportActionCompose/SuggestionMention.tsx Component Cannot access refs during render
    ReportActionItemMessageEdit pages/inbox/report/ReportActionItemMessageEdit.tsx Component Cannot access refs during render
    WithReportOrNotFound pages/inbox/report/withReportOrNotFound.tsx Component Cannot access refs during render
    IOURequestStepConfirmationContent pages/iou/request/step/IOURequestStepConfirmation/index.tsx Component Existing memoization could not be preserved
    AboutPage pages/settings/AboutPage/AboutPage.tsx Component Existing memoization could not be preserved
    DynamicContactMethodDetailsPage pages/settings/Profile/Contacts/DynamicContactMethodDetailsPage.tsx Component Cannot access refs during render
    DynamicNewContactMethodPage pages/settings/Profile/Contacts/DynamicNewContactMethodPage.tsx Component Existing memoization could not be preserved
    DebitCardPage pages/settings/Wallet/AddDebitCardPage.tsx Component Support functions with unreachable code that may contain hoisted declarations
    WorkspacePageWithSections pages/workspace/WorkspacePageWithSections.tsx Component Existing memoization could not be preserved
    DynamicWorkspaceOwnerChangeErrorPage pages/workspace/members/DynamicWorkspaceOwnerChangeErrorPage.tsx Component Cannot access refs during render
    DynamicWorkspaceOwnerChangeSuccessPage pages/workspace/members/DynamicWorkspaceOwnerChangeSuccessPage.tsx Component Cannot access refs during render
    ImportedMembersConfirmationPage pages/workspace/members/ImportedMembersConfirmationPage.tsx Component Cannot access refs during render
    useActionSheetAwareScrollViewRef components/ActionSheetAwareScrollView/useActionSheetAwareScrollViewRef.ts Hook This value cannot be modified
    usePromptContent components/MultifactorAuthentication/Context/usePromptContent.ts Hook Cannot access refs during render
    useAutoCreateTrackWorkspace hooks/useAutoCreateTrackWorkspace.ts Hook Limitation: Handle TryStatement with a finalizer ('finally') clause
    useCancellationType hooks/useCancellationType.ts Hook Cannot access refs during render
    useFirstRenderRoute hooks/useFirstRenderRoute.ts Hook Limitation: Handle get functions in ObjectExpression
    useHtmlPaste hooks/useHtmlPaste/index.ts Hook Limitation: Expression type BinaryExpression cannot be safely reordered
    useInitial hooks/useInitial.ts Hook Cannot access refs during render
    useIsOwnWorkspaceChatRef hooks/useIsOwnWorkspaceChatRef.ts Hook Cannot access refs during render
    useNewTransactions hooks/useNewTransactions.ts Hook Cannot access refs during render
    usePaginatedReportActions hooks/usePaginatedReportActions.ts Hook Cannot access refs during render
    usePaymentOptions hooks/usePaymentOptions.ts Hook Cannot access refs during render
    usePermissions hooks/usePermissions.ts Hook Expected a StoreLocal or Destructure in for..in collection, found Discriminant(29)
    usePrevious hooks/usePrevious.ts Hook Cannot access refs during render
    usePreviousDefined hooks/usePreviousDefined.ts Hook Cannot access refs during render
    useSearchBulkActions hooks/useSearchBulkActions.ts Hook Cannot access refs during render
    useSelectedTransactionsActions hooks/useSelectedTransactionsActions.ts Hook Cannot access refs during render
    useSingleExecution hooks/useSingleExecution/index.native.ts Hook Cannot access refs during render
    useSingleExecution hooks/useSingleExecution/index.ts Hook Expected temporaries to be promoted to named identifiers in an earlier pass
    useReportUnreadMessageScrollTracking pages/inbox/report/useReportUnreadMessageScrollTracking.ts Hook Existing memoization could not be preserved

    view run

  13. roryabraham commented on Oct 20, 2026

    @roryabraham
    ContributorAuthor
  14. roryabraham commented on Oct 20, 2026

    @roryabraham
    ContributorAuthor

    My plan is to implement this proposal, then hopefully close this issue as completed.

  15. melvin-bot commented on Oct 23, 2026

    @melvin-bot

    @chrispader, @roryabraham, @situchan Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

  16. melvin-bot commented on Oct 27, 2026

    @melvin-bot

    @chrispader, @roryabraham, @situchan 6 days overdue. This is scarier than being forced to listen to Vogon poetry!

  17. roryabraham commented on Oct 27, 2026

    @roryabraham
    ContributorAuthor

    #104514 is merged on main, which both:

    1. Disallowed manual memoization from components that compile with React Compiler
    2. Removed manual memoization from all such components.

    Once that makes it to production, imo we can close this issue out.

  18. chrispader commented on Oct 28, 2026

    @chrispader
    Contributor

    Once that makes it to production, imo we can close this issue out.

    Yes sounds good! Awesome work @roryabraham 🙌🏼

  19. roryabraham commented on Oct 29, 2026

    @roryabraham
    ContributorAuthor

    Closing this as complete 🎉

  20. roryabraham commented on Oct 29, 2026

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

Metadata

Metadata

Labels

BugSomething is broken. Auto assigns a BugZero manager.DailyKSv2ImprovementItem broken or needs improvement.Skip PaymentSkips all the payment process steps for an issue. Use it for fixed-price projects.

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions