From 53b361a99debb978eeb18e4d4fdcd172d6d5efcb Mon Sep 17 00:00:00 2001 From: claygeo Date: Mon, 30 Mar 2026 11:10:51 -0400 Subject: [PATCH 1/2] fix(react): usePGlite returns null instead of throwing outside provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously calling usePGlite() without a PGliteProvider ancestor threw a runtime error. This made it impossible to use pglite conditionally or in components that render before the provider mounts. Change the hook to return null when no provider is found. The type signature is updated from T to T | null so TypeScript enforces null checks at the call site — callers guard with `if (!db) return`. The explicit-db override path (usePGlite(db)) is unchanged. Fixes: https://github.com/electric-sql/pglite/issues/878 --- packages/pglite-react/src/provider.tsx | 11 ++++------- packages/pglite-react/test/provider.test.tsx | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/pglite-react/src/provider.tsx b/packages/pglite-react/src/provider.tsx index f1b5f70e2..ffc865fcf 100644 --- a/packages/pglite-react/src/provider.tsx +++ b/packages/pglite-react/src/provider.tsx @@ -9,7 +9,7 @@ interface Props { type PGliteProvider = ( props: Props, ) => React.JSX.Element -type UsePGlite = (db?: T) => T +type UsePGlite = (db?: T) => T | null interface PGliteProviderSet { PGliteProvider: PGliteProvider @@ -28,12 +28,9 @@ function makePGliteProvider(): PGliteProviderSet { // allow providing a db explicitly if (db !== undefined) return db - if (!dbProvided) - throw new Error( - 'No PGlite instance found, use PGliteProvider to provide one', - ) - - return dbProvided + // Return null instead of throwing when no provider is mounted. + // Callers can guard with `if (!db) return` for lazy / conditional rendering. + return dbProvided ?? null }) as UsePGlite, PGliteProvider: ({ children, db }: Props) => { return {children} diff --git a/packages/pglite-react/test/provider.test.tsx b/packages/pglite-react/test/provider.test.tsx index 651052e60..dd5661d94 100644 --- a/packages/pglite-react/test/provider.test.tsx +++ b/packages/pglite-react/test/provider.test.tsx @@ -41,3 +41,20 @@ describe('provider', () => { await waitFor(() => expect(result.current).toBe(db)) }) }) + +describe('usePGlite outside provider', () => { + it('returns null when no PGliteProvider is mounted', () => { + const { result } = renderHook(() => usePGlite()) + expect(result.current).toBeNull() + }) + + it('does not throw when no PGliteProvider is mounted', () => { + expect(() => renderHook(() => usePGlite())).not.toThrow() + }) + + it('returns the db when provided directly as argument', async () => { + const db = await PGlite.create({ extensions: { live } }) + const { result } = renderHook(() => usePGlite(db as PGliteWithLive)) + expect(result.current).toBe(db) + }) +}) From da87481c2bd70bde984386022e65649b955f4e4f Mon Sep 17 00:00:00 2001 From: claygeo Date: Mon, 30 Mar 2026 11:15:24 -0400 Subject: [PATCH 2/2] fix(react): guard live query hooks against null db from usePGlite Since usePGlite now returns null outside a provider instead of throwing, hooks that call db.live.query() would crash with a TypeError on null dereference. Add an early return in the useEffect so subscriptions are simply skipped when no provider is mounted. --- packages/pglite-react/src/hooks.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/pglite-react/src/hooks.ts b/packages/pglite-react/src/hooks.ts index 5bf90d313..765fedeb3 100644 --- a/packages/pglite-react/src/hooks.ts +++ b/packages/pglite-react/src/hooks.ts @@ -44,6 +44,7 @@ function useLiveQueryImpl( /* eslint-disable @eslint-react/hooks-extra/no-direct-set-state-in-use-effect */ useEffect(() => { + if (!db) return // no PGliteProvider mounted — skip subscription let cancelled = false const cb = (results: LiveQueryResults) => { if (cancelled) return