Skip to content

refactor: Fix React Compiler violations across Reactist #1066

@frankieyan

Description

@frankieyan

⁉️ Why

We have 8 modules tracked in .react-compiler.rec.json. Fixing them lets the compiler memoize those modules automatically and pushes us toward the better React patterns the compiler expects.

🗺 Overview

Each sub-issue tracks a single module from .react-compiler.rec.json. To close one:

  1. Find the violations. Run npx @doist/react-compiler-tracker --check-files --show-errors <file> to list each violation's line number and reason. (--show-errors needs tracker 2.2.0+; the repo currently pins 2.1.2, so use @latest or bump the dep.)
  2. Fix them. Use the patterns in docs/react-guidelines/react-compiler.md. The Error reference table maps each compiler message to its fix-pattern section.
  3. Confirm the count dropped. npx @doist/react-compiler-tracker --check-files <file> reports the decrease. This command is read-only; the pre-commit hook (lint-staged.config.js, npx @doist/react-compiler-tracker --stage-record-file) is what removes the file's entry from .react-compiler.rec.json.
  4. Verify memoization landed. A clean tracker run alone does not prove it: the compiler can silently skip memoization with no error. Inspect the compiled output and confirm the memo slots (const $ = _c(N) and the $[n] !== value cache guards) cover the values that should be memoized.
  5. Document new patterns. If a fix is not covered by the docs, add it to shared/react-guidelines/react-compiler.md in Doist/shared-configs, which syncs back into this repo's docs/.

Once every sub-issue is closed, the only entry left in .react-compiler.rec.json should be the won't-fix module under Out of scope (use-previous).

🚧 Potential problems / unknowns

  • Do not remove manual useMemo/useCallback while a file still has violations.
  • Fixing flagged violations in a component/hook may reveal additional violations that were not previously flagged.
  • AriaKit store hooks are the most common cause, and the fix is the same for all of them. Seven of the 13 violations (across menu, tabs, and tooltip) come from store.useState(...) (e.g. menuStore.useState('open'), including the optional-chained tabContextValue?.tabStore.useState('selectedId')). The fix is to migrate to useStoreState(store, key) from @ariakit/react, which Reactist already has (0.4.19). ✨ Fixing the three components together will clear more than half the list.
  • useId in common-helpers accesses refs during render as a render-persistent cache and is already @deprecated; the fix is likely to migrate callers to React 18's useId rather than patch it, which affects every consumer.

🔮 Out of scope / future improvements

  • src/hooks/use-previous/use-previous.ts: won't fix. The hook returns ref.current during render by design, where the ref was written by an effect on the previous render. That is the only way to implement "value from the previous render" in React today, and the compiler's own warning acknowledges the ref can be stale. Making it compiler-compatible would change its behavior, so we'll leave it tracked in .react-compiler.rec.json unless we migrate its use to a library.

📝 Related documents & discussions


Issue by violation type

Violation Sub-issues
Cannot access refs during render
Hooks must be the same function on every render (AriaKit store.useState)
Hooks must always be called in a consistent order (conditional hook)
React ESLint rules were disabled
Support destructuring of context variables
LogicalExpression cannot be safely reordered

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions