FirebaseExtended / FirebaseExtended/reactfire
Suspense mode resumes with the previous observable's value on React 19
- Langage dominant
- TypeScript
- Étoiles
- 3.6k
- Forks
- 403
- Merge moyen
- 14 h 53 min
- PR mergées (30 j)
- 5
Description
`useObservable` in suspense mode suspends correctly when the observable and `observableId` are swapped, then resumes rendering the **previous** observable's value.
Found by the first test run ever executed against React 19 (#789); nothing had run against 19 before, only type-checks.
## Reproduction
`test/useObservable.test.tsx`, `emits the new observable's value if the observable is swapped out`. The test renders a component under `React.Suspense`, emits `Jeff` on the first observable, swaps both the observable and the `observableId`, rerenders, then emits `James` on the second.
- **React 18.2.0:** the fallback shows, then the component resumes with `James`. Passes.
- **React 19.2.8:** the fallback shows (that assertion passes), then the component resumes with `Jeff`. Fails.
Deterministic: 3 runs each way, same `@testing-library/react` 16.3.2, only the React runtime swapped via `npm install --no-save react@19 react-dom@19`. No emulators involved, so `npx vitest run useObservable` reproduces it.
## What is known and not known
- The suspend half works. Only the resume is wrong, so this is not the known throw-vs-`use()` question: the 08-07 spike found the `use()` swap is a behavioural no-op on 19 and that React 19 emits no warning for the current throw form. Nothing here contradicts that.
- **The cause is not diagnosed.** The plumbing involved (`SuspenseSubject`, the `preloadedObservables` cache keyed by `observableId`, and the `use-sync-external-store` shim delegating to React's own `useSyncExternalStore` on 19) overlaps what #790 covers, but no connection has been established and it should not be assumed.
## Current state
#789's CI PR skips this test on React 19 only, so the new test job can land green. The skip is a `? it.skip : it` ternary rather than `it.skipIf`, because these globals are typed by `@types/jest` and `skipIf` fails `tsc` while working at runtime.
Restore it to a plain `it` when this is fixed.
Guide de contribution
Ouvrir le guide de contribution
Piste de recherche
Run `npx vitest run useObservable` and start with `test/useObservable.test.tsx`, especially `emits the new observable's value if the observable is swapped out`. Trace the named `SuspenseSubject`, `preloadedObservables` cache, and `use-sync-external-store` path. Done means the test is restored to plain `it` and passes under React 19 while retaining the React 18 behavior.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- react, typescript
- Domaine
- frontend
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- Calme
- Clarté
- Plutôt claire
- Accessibilité débutants
- 48/100