Skip to content

feat(react): add usePGliteOptional for use outside a provider#953

Open
claygeo wants to merge 1 commit into
electric-sql:mainfrom
claygeo:fix/usepglite-null-outside-provider
Open

feat(react): add usePGliteOptional for use outside a provider#953
claygeo wants to merge 1 commit into
electric-sql:mainfrom
claygeo:fix/usepglite-null-outside-provider

Conversation

@claygeo

@claygeo claygeo commented Mar 30, 2026

Copy link
Copy Markdown
Contributor

Problem

Calling usePGlite() without a <PGliteProvider> ancestor throws:

Error: No PGlite instance found, use PGliteProvider to provide one

When the database is created asynchronously (lazy load, code-split, optional feature), components can render before the provider mounts, and the throw crashes the tree. This is issue #878, with a second report in the thread.

Approach

This revision keeps usePGlite() exactly as-is instead of changing its return type. usePGlite(): T still throws when no provider is mounted, so:

  • every existing call site keeps working,
  • the documented const db = usePGlite(); db.query(...) pattern still type-checks,
  • the existing provider.test-d.tsx contract expectTypeOf(usePGlite()).toEqualTypeOf<T>() stays green.

It adds an opt-in escape hatch instead:

  • usePGliteOptional(): T | null returns null rather than throwing when there is no provider. makePGliteProvider() returns it too, so typed providers get a typed optional hook.
  • Live query hooks: useLiveQueryImpl now resolves the db with usePGliteOptional(). The string-query branch clears results and skips the subscription (reporting undefined) until a provider mounts, then subscribes automatically since db is in the effect deps. The LiveQuery and promise overloads are unchanged; they never needed the context db.

Tests / docs

  • provider.test.tsx: usePGlite() still throws outside a provider; usePGliteOptional() returns null, does not throw, and honors an explicit db argument.
  • provider.test-d.tsx: adds expectTypeOf(usePGliteOptional()).toEqualTypeOf<T | null>() plus the wrong-extension @ts-expect-error, alongside the unchanged usePGlite() assertion.
  • Docs + README: new usePGliteOptional section.
  • Changeset: minor bump for @electric-sql/pglite-react.

Closes #878.

Resolves electric-sql#878. Components that render before an async or lazy
PGliteProvider mounts currently crash because usePGlite() throws. This
adds an opt-in usePGliteOptional() hook that returns null in that case,
and makes the string-query form of useLiveQuery / useLiveIncrementalQuery
tolerate a not-yet-mounted provider (returning undefined until one
appears) instead of throwing.

usePGlite() is unchanged: same return type T, same throw-on-missing-
provider behavior, so no existing call site or the provider.test-d.tsx
type contract breaks.
@claygeo claygeo force-pushed the fix/usepglite-null-outside-provider branch from da87481 to 4f3e3ab Compare June 19, 2026 14:20
@claygeo claygeo changed the title fix(react): usePGlite returns null instead of throwing outside provider feat(react): add usePGliteOptional for use outside a provider Jun 19, 2026
@claygeo

claygeo commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Friendly nudge on this one, and a heads-up that I have reworked it since it was first opened.

I rebased onto current main and changed the approach to be non-breaking. usePGlite() is now left exactly as-is (still returns T, still throws outside a provider), so existing call sites and the provider.test-d.tsx type contract are untouched. The fix is now an opt-in usePGliteOptional(): T | null hook, plus the string-query form of useLiveQuery/useLiveIncrementalQuery returning undefined instead of throwing until a provider mounts. Tests, docs, and a changeset are included.

This resolves #878 (two people hit it). Happy to rename the hook or split the docs change out if you'd prefer. Would appreciate a review when you have a moment.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

React: Don't throw an error when usePGlite() doesn't find a PGlite instance

1 participant