Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

Fast Refresh doesn't reset the React Compiler memo cache from c()

Geschlossen Anfängerfreundlich
#69 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
82/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
react, typescript
Bereich
frontend

Rechercherichtung

Beginne mit src/react/compiler-runtime.ts und untersuche, wie c() seinen Memo-Cache speichert; vergleiche das mit der Behandlung von Refresh in src/dom/dispatcher.ts. Füge die Reproduktion zu tests/fast-refresh.test.tsx hinzu und überprüfe, dass die aktualisierte Komponente after:1 und dann after:2 anzeigt, während der Zustand erhalten bleibt. Laut Issue bestehen dieser Test und die gesamte Testsuite mit der vorgeschlagenen Änderung.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

Summary

After a Fast Refresh update, components compiled by React Compiler keep rendering their old output. The compiler runtime's c() keeps its memo cache across the refresh, so cached JSX from the previous version of the component is returned until a full reload.

React resets this cache on refresh. In development, renderWithHooks sets ignorePreviousDependencies when the fiber's type changed, and useMemoCache then refills the cache with sentinels (ReactFiberHooks.js).

Reproduction

Added to tests/fast-refresh.test.tsx. The component is written the way the compiler emits it:

import { c } from 'react/compiler-runtime'

it('resets the React Compiler memo cache but preserves state', () => {
  function version(label: string) {
    return function Example() {
      const $ = c(3)
      const [count, setCount] = useState(0)
      let t0
      if ($[0] === Symbol.for('react.memo_cache_sentinel')) {
        t0 = () => setCount(n => n + 1)
        $[0] = t0
      } else t0 = $[0] as () => void
      let t1
      if ($[1] !== count) {
        t1 = <button onClick={t0}>{label}:{count}</button>
        $[1] = count
        $[2] = t1
      } else t1 = $[2]
      return t1
    }
  }
  const Before = version('before'), update = family(Before, 'stable')
  const { container } = setup(<Before />)
  click(container)
  update(version('after'))
  Refresh.performReactRefresh()
  expect(container.textContent).toBe('after:1')
  click(container)
  expect(container.textContent).toBe('after:2')
})

On main it fails with expected 'before:1' to be 'after:1'.

Cause

c() in src/react/compiler-runtime.ts stores the cache in a useRef, which survives the refresh. useMemo and useCallback already handle this case: depsEqual returns false while the fiber is refreshing.

Babel's compiler hides the bug in development because it also emits a source-hash check that clears the cache whenever the file changes. The Rust port in oxc-transform-react, which @vitejs/plugin-react uses for react({ compiler: true }), doesn't emit that check, so with it every hot update of a compiled component is stale.

Suggested fix

Back c() with useMemo, so it picks up the existing refresh handling in depsEqual:

export function c(size: number): Array<unknown> {
  return useMemo(() => new Array<unknown>(size).fill(MEMO_CACHE_SENTINEL), [size])
}

With this change the test above passes and the rest of the suite still passes (1860 passed, 91 skipped).

Versions
  • @tanstack/redact 0.2.0, and main at d56d87cb
  • react-refresh 0.19.0 (from the test suite)
  • oxc-transform-react 0.155.0 with @vitejs/plugin-react 6.1.2, where we first hit it

Disclaimer: this issue, including the reproduction test and the suggested fix, was researched and written by Claude, an AI assistant from Anthropic.

Vorherrschende Sprache
TypeScript
Sterne
408
Forks
13
Ø Merge
1 Std. 44 Min.
Gemergte PRs (30 T.)
21

Entwicklungsumgebung

Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus TanStack/redact

Alle Issues in TanStack/redact

Ähnliche Issues

Weitere Issues zu TypeScript

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.