Fast Refresh doesn't reset the React Compiler memo cache from c()
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/redact0.2.0, andmainat d56d87cbreact-refresh0.19.0 (from the test suite)oxc-transform-react0.155.0 with@vitejs/plugin-react6.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
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus TanStack/redact
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 88/100
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 90/100
TanStack/redact#67 · 1 Reaktion ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 82/100
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in TanStack/redact
Ähnliche Issues
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
gnosis/gnosis_vpn#661 ·
Maintainer antworten meist innerhalb von 1 Tag
-
content-freshness: staleOwnedContent doc comments still say 'complete receipt' (follow-up to #7912)Offentriage:bug-verified
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 92/100
Maintainer antworten meist innerhalb von 1 Tag
-
fix: reject sourceStorage/packagedStorage bucket that differs from the stack default (fail loud)Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
Eyevinn/open-videocore#1300 ·
Maintainer antworten meist innerhalb von 1 Tag
-
nextjs-tracking
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 67/100
cloudflare/vinext#4390 ·
Maintainer antworten meist innerhalb von 1 Tag
-
kind/bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
kubernetes-sigs/headlamp#8175 ·
Maintainer antworten meist innerhalb von 2 Tagen